LCOV - code coverage report
Current view: directory - netwerk/dns - nsDNSService2.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 319 221 69.3 %
Date: 2012-06-02 Functions: 48 39 81.2 %

       1                 : /* vim:set ts=4 sw=4 sts=4 et cin: */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is Mozilla.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is IBM Corporation.
      18                 :  * Portions created by IBM Corporation are Copyright (C) 2003
      19                 :  * IBM Corporation. All Rights Reserved.
      20                 :  *
      21                 :  * Contributor(s):
      22                 :  *   IBM Corp.
      23                 :  *
      24                 :  * Alternatively, the contents of this file may be used under the terms of
      25                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      26                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      27                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      28                 :  * of those above. If you wish to allow use of your version of this file only
      29                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      30                 :  * use your version of this file under the terms of the MPL, indicate your
      31                 :  * decision by deleting the provisions above and replace them with the notice
      32                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      33                 :  * the provisions above, a recipient may use your version of this file under
      34                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      35                 :  *
      36                 :  * ***** END LICENSE BLOCK ***** */
      37                 : 
      38                 : #include "nsDNSService2.h"
      39                 : #include "nsIDNSRecord.h"
      40                 : #include "nsIDNSListener.h"
      41                 : #include "nsICancelable.h"
      42                 : #include "nsIPrefService.h"
      43                 : #include "nsIPrefBranch.h"
      44                 : #include "nsIServiceManager.h"
      45                 : #include "nsProxyRelease.h"
      46                 : #include "nsReadableUtils.h"
      47                 : #include "nsString.h"
      48                 : #include "nsAutoPtr.h"
      49                 : #include "nsNetCID.h"
      50                 : #include "nsNetError.h"
      51                 : #include "nsDNSPrefetch.h"
      52                 : #include "nsThreadUtils.h"
      53                 : #include "nsIProtocolProxyService.h"
      54                 : #include "prsystem.h"
      55                 : #include "prnetdb.h"
      56                 : #include "prmon.h"
      57                 : #include "prio.h"
      58                 : #include "plstr.h"
      59                 : #include "nsIOService.h"
      60                 : 
      61                 : #include "mozilla/FunctionTimer.h"
      62                 : 
      63                 : using namespace mozilla;
      64                 : 
      65                 : static const char kPrefDnsCacheEntries[]    = "network.dnsCacheEntries";
      66                 : static const char kPrefDnsCacheExpiration[] = "network.dnsCacheExpiration";
      67                 : static const char kPrefDnsCacheGrace[]      = "network.dnsCacheExpirationGracePeriod";
      68                 : static const char kPrefEnableIDN[]          = "network.enableIDN";
      69                 : static const char kPrefIPv4OnlyDomains[]    = "network.dns.ipv4OnlyDomains";
      70                 : static const char kPrefDisableIPv6[]        = "network.dns.disableIPv6";
      71                 : static const char kPrefDisablePrefetch[]    = "network.dns.disablePrefetch";
      72                 : 
      73                 : //-----------------------------------------------------------------------------
      74                 : 
      75                 : class nsDNSRecord : public nsIDNSRecord
      76                 : {
      77                 : public:
      78                 :     NS_DECL_ISUPPORTS
      79                 :     NS_DECL_NSIDNSRECORD
      80                 : 
      81            6205 :     nsDNSRecord(nsHostRecord *hostRecord)
      82                 :         : mHostRecord(hostRecord)
      83                 :         , mIter(nsnull)
      84                 :         , mLastIter(nsnull)
      85                 :         , mIterGenCnt(-1)
      86            6205 :         , mDone(false) {}
      87                 : 
      88                 : private:
      89           24820 :     virtual ~nsDNSRecord() {}
      90                 : 
      91                 :     nsRefPtr<nsHostRecord>  mHostRecord;
      92                 :     void                   *mIter;       // enum ptr for PR_EnumerateAddrInfo
      93                 :     void                   *mLastIter;   // previous enum ptr, for use in
      94                 :                                          // getting addrinfo in ReportUnusable
      95                 :     int                     mIterGenCnt; // the generation count of
      96                 :                                          // mHostRecord->addr_info when we
      97                 :                                          // start iterating
      98                 :     bool                    mDone;
      99                 : };
     100                 : 
     101           52126 : NS_IMPL_THREADSAFE_ISUPPORTS1(nsDNSRecord, nsIDNSRecord)
     102                 : 
     103                 : NS_IMETHODIMP
     104               0 : nsDNSRecord::GetCanonicalName(nsACString &result)
     105                 : {
     106                 :     // this method should only be called if we have a CNAME
     107               0 :     NS_ENSURE_TRUE(mHostRecord->flags & nsHostResolver::RES_CANON_NAME,
     108                 :                    NS_ERROR_NOT_AVAILABLE);
     109                 : 
     110                 :     // if the record is for an IP address literal, then the canonical
     111                 :     // host name is the IP address literal.
     112                 :     const char *cname;
     113                 :     {
     114               0 :         MutexAutoLock lock(mHostRecord->addr_info_lock);
     115               0 :         if (mHostRecord->addr_info)
     116               0 :             cname = PR_GetCanonNameFromAddrInfo(mHostRecord->addr_info);
     117                 :         else
     118               0 :             cname = mHostRecord->host;
     119               0 :         result.Assign(cname);
     120                 :     }
     121               0 :     return NS_OK;
     122                 : }
     123                 : 
     124                 : NS_IMETHODIMP
     125            3143 : nsDNSRecord::GetNextAddr(PRUint16 port, PRNetAddr *addr)
     126                 : {
     127                 :     // not a programming error to poke the DNS record when it has no more
     128                 :     // entries.  just fail without any debug warnings.  this enables consumers
     129                 :     // to enumerate the DNS record without calling HasMore.
     130            3143 :     if (mDone)
     131              68 :         return NS_ERROR_NOT_AVAILABLE;
     132                 : 
     133            3075 :     mHostRecord->addr_info_lock.Lock();
     134            3075 :     bool startedFresh = !mIter;
     135                 : 
     136            3075 :     if (mHostRecord->addr_info) {
     137            2987 :         if (!mIter)
     138            2919 :             mIterGenCnt = mHostRecord->addr_info_gencnt;
     139              68 :         else if (mIterGenCnt != mHostRecord->addr_info_gencnt) {
     140                 :             // mHostRecord->addr_info has changed, so mIter is invalid.
     141                 :             // Restart the iteration.  Alternatively, we could just fail.
     142               0 :             mIter = nsnull;
     143               0 :             mIterGenCnt = mHostRecord->addr_info_gencnt;
     144               0 :             startedFresh = true;
     145                 :         }
     146                 : 
     147            5956 :         do {
     148            3037 :             mLastIter = mIter;
     149            3037 :             mIter = PR_EnumerateAddrInfo(mIter, mHostRecord->addr_info,
     150            6074 :                                          port, addr);
     151                 :         }
     152            2919 :         while (mIter && mHostRecord->Blacklisted(addr));
     153                 : 
     154            2987 :         if (startedFresh && !mIter) {
     155                 :             // if everything was blacklisted we want to reset the blacklist (and
     156                 :             // likely relearn it) and return the first address. That is better
     157                 :             // than nothing
     158              50 :             mHostRecord->ResetBlacklist();
     159              50 :             mLastIter = nsnull;
     160              50 :             mIter = PR_EnumerateAddrInfo(nsnull, mHostRecord->addr_info,
     161             100 :                                          port, addr);
     162                 :         }
     163                 :             
     164            2987 :         mHostRecord->addr_info_lock.Unlock();
     165            2987 :         if (!mIter) {
     166              68 :             mDone = true;
     167              68 :             return NS_ERROR_NOT_AVAILABLE;
     168                 :         }
     169                 :     }
     170                 :     else {
     171              88 :         mHostRecord->addr_info_lock.Unlock();
     172              88 :         if (!mHostRecord->addr) {
     173                 :             // Both mHostRecord->addr_info and mHostRecord->addr are null.
     174                 :             // This can happen if mHostRecord->addr_info expired and the
     175                 :             // attempt to reresolve it failed.
     176               0 :             return NS_ERROR_NOT_AVAILABLE;
     177                 :         }
     178              88 :         memcpy(addr, mHostRecord->addr, sizeof(PRNetAddr));
     179                 :         // set given port
     180              88 :         port = PR_htons(port);
     181              88 :         if (addr->raw.family == PR_AF_INET)
     182              88 :             addr->inet.port = port;
     183                 :         else
     184               0 :             addr->ipv6.port = port;
     185              88 :         mDone = true; // no iterations
     186                 :     }
     187                 :         
     188            3007 :     return NS_OK; 
     189                 : }
     190                 : 
     191                 : NS_IMETHODIMP
     192               1 : nsDNSRecord::GetNextAddrAsString(nsACString &result)
     193                 : {
     194                 :     PRNetAddr addr;
     195               1 :     nsresult rv = GetNextAddr(0, &addr);
     196               1 :     if (NS_FAILED(rv)) return rv;
     197                 : 
     198                 :     char buf[64];
     199               1 :     if (PR_NetAddrToString(&addr, buf, sizeof(buf)) == PR_SUCCESS) {
     200               1 :         result.Assign(buf);
     201               1 :         return NS_OK;
     202                 :     }
     203               0 :     NS_ERROR("PR_NetAddrToString failed unexpectedly");
     204               0 :     return NS_ERROR_FAILURE; // conversion failed for some reason
     205                 : }
     206                 : 
     207                 : NS_IMETHODIMP
     208               0 : nsDNSRecord::HasMore(bool *result)
     209                 : {
     210               0 :     if (mDone)
     211               0 :         *result = false;
     212                 :     else {
     213                 :         // unfortunately, NSPR does not provide a way for us to determine if
     214                 :         // there is another address other than to simply get the next address.
     215               0 :         void *iterCopy = mIter;
     216               0 :         void *iterLastCopy = mLastIter;
     217                 :         PRNetAddr addr;
     218               0 :         *result = NS_SUCCEEDED(GetNextAddr(0, &addr));
     219               0 :         mIter = iterCopy; // backup iterator
     220               0 :         mLastIter = iterLastCopy; // backup iterator
     221               0 :         mDone = false;
     222                 :     }
     223               0 :     return NS_OK;
     224                 : }
     225                 : 
     226                 : NS_IMETHODIMP
     227               0 : nsDNSRecord::Rewind()
     228                 : {
     229               0 :     mIter = nsnull;
     230               0 :     mLastIter = nsnull;
     231               0 :     mIterGenCnt = -1;
     232               0 :     mDone = false;
     233               0 :     return NS_OK;
     234                 : }
     235                 : 
     236                 : NS_IMETHODIMP
     237             136 : nsDNSRecord::ReportUnusable(PRUint16 aPort)
     238                 : {
     239                 :     // right now we don't use the port in the blacklist
     240                 : 
     241             136 :     mHostRecord->addr_info_lock.Lock();
     242                 : 
     243                 :     // Check that we are using a real addr_info (as opposed to a single
     244                 :     // constant address), and that the generation count is valid. Otherwise,
     245                 :     // ignore the report.
     246                 : 
     247             204 :     if (mHostRecord->addr_info &&
     248              68 :         mIterGenCnt == mHostRecord->addr_info_gencnt) {
     249                 :         PRNetAddr addr;
     250              68 :         void *id = PR_EnumerateAddrInfo(mLastIter, mHostRecord->addr_info,
     251             136 :                                         aPort, &addr);
     252              68 :         if (id)
     253              68 :             mHostRecord->ReportUnusable(&addr);
     254                 :     }
     255                 :     
     256             136 :     mHostRecord->addr_info_lock.Unlock();
     257             136 :     return NS_OK;
     258                 : }
     259                 : 
     260                 : //-----------------------------------------------------------------------------
     261                 : 
     262                 : class nsDNSAsyncRequest : public nsResolveHostCallback
     263                 :                         , public nsICancelable
     264                 : {
     265                 : public:
     266                 :     NS_DECL_ISUPPORTS
     267                 :     NS_DECL_NSICANCELABLE
     268                 : 
     269            6492 :     nsDNSAsyncRequest(nsHostResolver   *res,
     270                 :                       const nsACString &host,
     271                 :                       nsIDNSListener   *listener,
     272                 :                       PRUint16          flags,
     273                 :                       PRUint16          af)
     274                 :         : mResolver(res)
     275                 :         , mHost(host)
     276                 :         , mListener(listener)
     277                 :         , mFlags(flags)
     278            6492 :         , mAF(af) {}
     279            6492 :     ~nsDNSAsyncRequest() {}
     280                 : 
     281                 :     void OnLookupComplete(nsHostResolver *, nsHostRecord *, nsresult);
     282                 :     // Returns TRUE if the DNS listener arg is the same as the member listener
     283                 :     // Used in Cancellations to remove DNS requests associated with a
     284                 :     // particular hostname and nsIDNSListener
     285                 :     bool EqualsAsyncListener(nsIDNSListener *aListener);
     286                 : 
     287                 :     nsRefPtr<nsHostResolver> mResolver;
     288                 :     nsCString                mHost; // hostname we're resolving
     289                 :     nsCOMPtr<nsIDNSListener> mListener;
     290                 :     PRUint16                 mFlags;
     291                 :     PRUint16                 mAF;
     292                 : };
     293                 : 
     294                 : void
     295            6492 : nsDNSAsyncRequest::OnLookupComplete(nsHostResolver *resolver,
     296                 :                                     nsHostRecord   *hostRecord,
     297                 :                                     nsresult        status)
     298                 : {
     299                 :     // need to have an owning ref when we issue the callback to enable
     300                 :     // the caller to be able to addref/release multiple times without
     301                 :     // destroying the record prematurely.
     302           12984 :     nsCOMPtr<nsIDNSRecord> rec;
     303            6492 :     if (NS_SUCCEEDED(status)) {
     304            6204 :         NS_ASSERTION(hostRecord, "no host record");
     305            6204 :         rec = new nsDNSRecord(hostRecord);
     306            6204 :         if (!rec)
     307               0 :             status = NS_ERROR_OUT_OF_MEMORY;
     308                 :     }
     309                 : 
     310            6492 :     mListener->OnLookupComplete(this, rec, status);
     311            6492 :     mListener = nsnull;
     312                 : 
     313                 :     // release the reference to ourselves that was added before we were
     314                 :     // handed off to the host resolver.
     315            6492 :     NS_RELEASE_THIS();
     316            6492 : }
     317                 : 
     318                 : bool
     319               0 : nsDNSAsyncRequest::EqualsAsyncListener(nsIDNSListener *aListener)
     320                 : {
     321               0 :     return (aListener == mListener);
     322                 : }
     323                 : 
     324           51991 : NS_IMPL_THREADSAFE_ISUPPORTS1(nsDNSAsyncRequest, nsICancelable)
     325                 : 
     326                 : NS_IMETHODIMP
     327               0 : nsDNSAsyncRequest::Cancel(nsresult reason)
     328                 : {
     329               0 :     NS_ENSURE_ARG(NS_FAILED(reason));
     330               0 :     mResolver->DetachCallback(mHost.get(), mFlags, mAF, this, reason);
     331               0 :     return NS_OK;
     332                 : }
     333                 : 
     334                 : //-----------------------------------------------------------------------------
     335                 : 
     336                 : class nsDNSSyncRequest : public nsResolveHostCallback
     337                 : {
     338                 : public:
     339               1 :     nsDNSSyncRequest(PRMonitor *mon)
     340                 :         : mDone(false)
     341                 :         , mStatus(NS_OK)
     342               1 :         , mMonitor(mon) {}
     343               2 :     virtual ~nsDNSSyncRequest() {}
     344                 : 
     345                 :     void OnLookupComplete(nsHostResolver *, nsHostRecord *, nsresult);
     346                 :     bool EqualsAsyncListener(nsIDNSListener *aListener);
     347                 : 
     348                 :     bool                   mDone;
     349                 :     nsresult               mStatus;
     350                 :     nsRefPtr<nsHostRecord> mHostRecord;
     351                 : 
     352                 : private:
     353                 :     PRMonitor             *mMonitor;
     354                 : };
     355                 : 
     356                 : void
     357               1 : nsDNSSyncRequest::OnLookupComplete(nsHostResolver *resolver,
     358                 :                                    nsHostRecord   *hostRecord,
     359                 :                                    nsresult        status)
     360                 : {
     361                 :     // store results, and wake up nsDNSService::Resolve to process results.
     362               1 :     PR_EnterMonitor(mMonitor);
     363               1 :     mDone = true;
     364               1 :     mStatus = status;
     365               1 :     mHostRecord = hostRecord;
     366               1 :     PR_Notify(mMonitor);
     367               1 :     PR_ExitMonitor(mMonitor);
     368               1 : }
     369                 : 
     370                 : bool
     371               0 : nsDNSSyncRequest::EqualsAsyncListener(nsIDNSListener *aListener)
     372                 : {
     373                 :     // Sync request: no listener to compare
     374               0 :     return false;
     375                 : }
     376                 : 
     377                 : //-----------------------------------------------------------------------------
     378                 : 
     379            1419 : nsDNSService::nsDNSService()
     380                 :     : mLock("nsDNSServer.mLock")
     381            1419 :     , mFirstTime(true)
     382                 : {
     383            1419 : }
     384                 : 
     385            1416 : nsDNSService::~nsDNSService()
     386                 : {
     387            1416 : }
     388                 : 
     389          155846 : NS_IMPL_THREADSAFE_ISUPPORTS3(nsDNSService, nsIDNSService, nsPIDNSService,
     390                 :                               nsIObserver)
     391                 : 
     392                 : NS_IMETHODIMP
     393            2863 : nsDNSService::Init()
     394                 : {
     395                 :     NS_TIME_FUNCTION;
     396                 : 
     397            2863 :     NS_ENSURE_TRUE(!mResolver, NS_ERROR_ALREADY_INITIALIZED);
     398                 : 
     399                 :     // prefs
     400            2863 :     PRUint32 maxCacheEntries  = 400;
     401            2863 :     PRUint32 maxCacheLifetime = 2; // minutes
     402            2863 :     PRUint32 lifetimeGracePeriod = 1;
     403            2863 :     bool     enableIDN        = true;
     404            2863 :     bool     disableIPv6      = false;
     405            2863 :     bool     disablePrefetch  = false;
     406            2863 :     int      proxyType        = nsIProtocolProxyService::PROXYCONFIG_DIRECT;
     407                 :     
     408            5726 :     nsAdoptingCString ipv4OnlyDomains;
     409                 : 
     410                 :     // read prefs
     411            5726 :     nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
     412            2863 :     if (prefs) {
     413                 :         PRInt32 val;
     414            2863 :         if (NS_SUCCEEDED(prefs->GetIntPref(kPrefDnsCacheEntries, &val)))
     415               0 :             maxCacheEntries = (PRUint32) val;
     416            2863 :         if (NS_SUCCEEDED(prefs->GetIntPref(kPrefDnsCacheExpiration, &val)))
     417               0 :             maxCacheLifetime = val / 60; // convert from seconds to minutes
     418            2863 :         if (NS_SUCCEEDED(prefs->GetIntPref(kPrefDnsCacheGrace, &val)))
     419               0 :             lifetimeGracePeriod = val / 60; // convert from seconds to minutes
     420                 : 
     421                 :         // ASSUMPTION: pref branch does not modify out params on failure
     422            2863 :         prefs->GetBoolPref(kPrefEnableIDN, &enableIDN);
     423            2863 :         prefs->GetBoolPref(kPrefDisableIPv6, &disableIPv6);
     424            2863 :         prefs->GetCharPref(kPrefIPv4OnlyDomains, getter_Copies(ipv4OnlyDomains));
     425            2863 :         prefs->GetBoolPref(kPrefDisablePrefetch, &disablePrefetch);
     426                 : 
     427                 :         // If a manual proxy is in use, disable prefetch implicitly
     428            2863 :         prefs->GetIntPref("network.proxy.type", &proxyType);
     429                 :     }
     430                 : 
     431            2863 :     if (mFirstTime) {
     432            1419 :         mFirstTime = false;
     433                 : 
     434                 :         // register as prefs observer
     435            1419 :         if (prefs) {
     436            1419 :             prefs->AddObserver(kPrefDnsCacheEntries, this, false);
     437            1419 :             prefs->AddObserver(kPrefDnsCacheExpiration, this, false);
     438            1419 :             prefs->AddObserver(kPrefDnsCacheGrace, this, false);
     439            1419 :             prefs->AddObserver(kPrefEnableIDN, this, false);
     440            1419 :             prefs->AddObserver(kPrefIPv4OnlyDomains, this, false);
     441            1419 :             prefs->AddObserver(kPrefDisableIPv6, this, false);
     442            1419 :             prefs->AddObserver(kPrefDisablePrefetch, this, false);
     443                 : 
     444                 :             // Monitor these to see if there is a change in proxy configuration
     445                 :             // If a manual proxy is in use, disable prefetch implicitly
     446            1419 :             prefs->AddObserver("network.proxy.type", this, false);
     447                 :         }
     448                 :     }
     449                 : 
     450                 :     // we have to null out mIDN since we might be getting re-initialized
     451                 :     // as a result of a pref change.
     452            5726 :     nsCOMPtr<nsIIDNService> idn;
     453            2863 :     if (enableIDN)
     454            2863 :         idn = do_GetService(NS_IDNSERVICE_CONTRACTID);
     455                 : 
     456            2863 :     nsDNSPrefetch::Initialize(this);
     457                 : 
     458                 :     // Don't initialize the resolver if we're in offline mode.
     459                 :     // Later on, the IO service will reinitialize us when going online.
     460            2863 :     if (gIOService->IsOffline() && !gIOService->IsComingOnline())
     461            1419 :         return NS_OK;
     462                 : 
     463            2888 :     nsRefPtr<nsHostResolver> res;
     464                 :     nsresult rv = nsHostResolver::Create(maxCacheEntries,
     465                 :                                          maxCacheLifetime,
     466                 :                                          lifetimeGracePeriod,
     467            1444 :                                          getter_AddRefs(res));
     468            1444 :     if (NS_SUCCEEDED(rv)) {
     469                 :         // now, set all of our member variables while holding the lock
     470            2888 :         MutexAutoLock lock(mLock);
     471            1444 :         mResolver = res;
     472            1444 :         mIDN = idn;
     473            1444 :         mIPv4OnlyDomains = ipv4OnlyDomains; // exchanges buffer ownership
     474            1444 :         mDisableIPv6 = disableIPv6;
     475                 : 
     476                 :         // Disable prefetching either by explicit preference or if a manual proxy is configured 
     477            1444 :         mDisablePrefetch = disablePrefetch || (proxyType == nsIProtocolProxyService::PROXYCONFIG_MANUAL);
     478                 :     }
     479            1444 :     return rv;
     480                 : }
     481                 : 
     482                 : NS_IMETHODIMP
     483            1444 : nsDNSService::Shutdown()
     484                 : {
     485            2888 :     nsRefPtr<nsHostResolver> res;
     486                 :     {
     487            2888 :         MutexAutoLock lock(mLock);
     488            1444 :         res = mResolver;
     489            1444 :         mResolver = nsnull;
     490                 :     }
     491            1444 :     if (res)
     492            1444 :         res->Shutdown();
     493            1444 :     return NS_OK;
     494                 : }
     495                 : 
     496                 : namespace {
     497                 : 
     498                 : class DNSListenerProxy : public nsIDNSListener
     499                 : {
     500                 : public:
     501              11 :   DNSListenerProxy(nsIDNSListener* aListener, nsIEventTarget* aTargetThread)
     502                 :     : mListener(aListener)
     503              11 :     , mTargetThread(aTargetThread)
     504              11 :   { }
     505                 : 
     506              11 :   ~DNSListenerProxy()
     507              22 :   {
     508              22 :     nsCOMPtr<nsIThread> mainThread(do_GetMainThread());
     509              11 :     NS_ProxyRelease(mainThread, mListener);
     510              11 :   }
     511                 : 
     512                 :   NS_DECL_ISUPPORTS
     513                 :   NS_DECL_NSIDNSLISTENER
     514                 : 
     515                 :   class OnLookupCompleteRunnable : public nsRunnable
     516                 :   {
     517                 :   public:
     518              11 :     OnLookupCompleteRunnable(nsIDNSListener* aListener,
     519                 :                              nsICancelable* aRequest,
     520                 :                              nsIDNSRecord* aRecord,
     521                 :                              nsresult aStatus)
     522                 :       : mListener(aListener)
     523                 :       , mRequest(aRequest)
     524                 :       , mRecord(aRecord)
     525              11 :       , mStatus(aStatus)
     526              11 :     { }
     527                 : 
     528              22 :     ~OnLookupCompleteRunnable()
     529              22 :     {
     530              22 :       nsCOMPtr<nsIThread> mainThread(do_GetMainThread());
     531              11 :       NS_ProxyRelease(mainThread, mListener);
     532              44 :     }
     533                 : 
     534                 :     NS_DECL_NSIRUNNABLE
     535                 : 
     536                 :   private:
     537                 :     nsCOMPtr<nsIDNSListener> mListener;
     538                 :     nsCOMPtr<nsICancelable> mRequest;
     539                 :     nsCOMPtr<nsIDNSRecord> mRecord;
     540                 :     nsresult mStatus;
     541                 :   };
     542                 : 
     543                 : private:
     544                 :   nsCOMPtr<nsIDNSListener> mListener;
     545                 :   nsCOMPtr<nsIEventTarget> mTargetThread;
     546                 : };
     547                 : 
     548              66 : NS_IMPL_THREADSAFE_ISUPPORTS1(DNSListenerProxy, nsIDNSListener)
     549                 : 
     550                 : NS_IMETHODIMP
     551              11 : DNSListenerProxy::OnLookupComplete(nsICancelable* aRequest,
     552                 :                                    nsIDNSRecord* aRecord,
     553                 :                                    nsresult aStatus)
     554                 : {
     555                 :   nsRefPtr<OnLookupCompleteRunnable> r =
     556              33 :     new OnLookupCompleteRunnable(mListener, aRequest, aRecord, aStatus);
     557              11 :   return mTargetThread->Dispatch(r, NS_DISPATCH_NORMAL);
     558                 : }
     559                 : 
     560                 : NS_IMETHODIMP
     561              11 : DNSListenerProxy::OnLookupCompleteRunnable::Run()
     562                 : {
     563              11 :   mListener->OnLookupComplete(mRequest, mRecord, mStatus);
     564              11 :   return NS_OK;
     565                 : }
     566                 : 
     567                 : } // anonymous namespace
     568                 : 
     569                 : NS_IMETHODIMP
     570            6495 : nsDNSService::AsyncResolve(const nsACString  &hostname,
     571                 :                            PRUint32           flags,
     572                 :                            nsIDNSListener    *listener,
     573                 :                            nsIEventTarget    *target,
     574                 :                            nsICancelable    **result)
     575                 : {
     576                 :     // grab reference to global host resolver and IDN service.  beware
     577                 :     // simultaneous shutdown!!
     578           12990 :     nsRefPtr<nsHostResolver> res;
     579           12990 :     nsCOMPtr<nsIIDNService> idn;
     580                 :     {
     581           12990 :         MutexAutoLock lock(mLock);
     582                 : 
     583            6495 :         if (mDisablePrefetch && (flags & RESOLVE_SPECULATE))
     584               0 :             return NS_ERROR_DNS_LOOKUP_QUEUE_FULL;
     585                 : 
     586            6495 :         res = mResolver;
     587           12990 :         idn = mIDN;
     588                 :     }
     589            6495 :     if (!res)
     590               3 :         return NS_ERROR_OFFLINE;
     591                 : 
     592            6492 :     const nsACString *hostPtr = &hostname;
     593                 : 
     594                 :     nsresult rv;
     595           12984 :     nsCAutoString hostACE;
     596            6492 :     if (idn && !IsASCII(hostname)) {
     597               0 :         if (NS_SUCCEEDED(idn->ConvertUTF8toACE(hostname, hostACE)))
     598               0 :             hostPtr = &hostACE;
     599                 :     }
     600                 : 
     601            6492 :     if (target) {
     602              11 :       listener = new DNSListenerProxy(listener, target);
     603                 :     }
     604                 : 
     605            6492 :     PRUint16 af = GetAFForLookup(*hostPtr, flags);
     606                 : 
     607                 :     nsDNSAsyncRequest *req =
     608           12984 :             new nsDNSAsyncRequest(res, *hostPtr, listener, flags, af);
     609            6492 :     if (!req)
     610               0 :         return NS_ERROR_OUT_OF_MEMORY;
     611            6492 :     NS_ADDREF(*result = req);
     612                 : 
     613                 :     // addref for resolver; will be released when OnLookupComplete is called.
     614            6492 :     NS_ADDREF(req);
     615            6492 :     rv = res->ResolveHost(req->mHost.get(), flags, af, req);
     616            6492 :     if (NS_FAILED(rv)) {
     617               0 :         NS_RELEASE(req);
     618               0 :         NS_RELEASE(*result);
     619                 :     }
     620            6492 :     return rv;
     621                 : }
     622                 : 
     623                 : NS_IMETHODIMP
     624               0 : nsDNSService::CancelAsyncResolve(const nsACString  &aHostname,
     625                 :                                  PRUint32           aFlags,
     626                 :                                  nsIDNSListener    *aListener,
     627                 :                                  nsresult           aReason)
     628                 : {
     629                 :     // grab reference to global host resolver and IDN service.  beware
     630                 :     // simultaneous shutdown!!
     631               0 :     nsRefPtr<nsHostResolver> res;
     632               0 :     nsCOMPtr<nsIIDNService> idn;
     633                 :     {
     634               0 :         MutexAutoLock lock(mLock);
     635                 : 
     636               0 :         if (mDisablePrefetch && (aFlags & RESOLVE_SPECULATE))
     637               0 :             return NS_ERROR_DNS_LOOKUP_QUEUE_FULL;
     638                 : 
     639               0 :         res = mResolver;
     640               0 :         idn = mIDN;
     641                 :     }
     642               0 :     if (!res)
     643               0 :         return NS_ERROR_OFFLINE;
     644                 : 
     645               0 :     nsCString hostname(aHostname);
     646                 : 
     647               0 :     nsCAutoString hostACE;
     648               0 :     if (idn && !IsASCII(aHostname)) {
     649               0 :         if (NS_SUCCEEDED(idn->ConvertUTF8toACE(aHostname, hostACE)))
     650               0 :             hostname = hostACE;
     651                 :     }
     652                 : 
     653               0 :     PRUint16 af = GetAFForLookup(hostname, aFlags);
     654                 : 
     655               0 :     res->CancelAsyncRequest(hostname.get(), aFlags, af, aListener, aReason);
     656               0 :     return NS_OK;
     657                 : }
     658                 : 
     659                 : NS_IMETHODIMP
     660               1 : nsDNSService::Resolve(const nsACString &hostname,
     661                 :                       PRUint32          flags,
     662                 :                       nsIDNSRecord    **result)
     663                 : {
     664                 :     // grab reference to global host resolver and IDN service.  beware
     665                 :     // simultaneous shutdown!!
     666               2 :     nsRefPtr<nsHostResolver> res;
     667               2 :     nsCOMPtr<nsIIDNService> idn;
     668                 :     {
     669               2 :         MutexAutoLock lock(mLock);
     670               1 :         res = mResolver;
     671               1 :         idn = mIDN;
     672                 :     }
     673               1 :     NS_ENSURE_TRUE(res, NS_ERROR_OFFLINE);
     674                 : 
     675               1 :     const nsACString *hostPtr = &hostname;
     676                 : 
     677                 :     nsresult rv;
     678               2 :     nsCAutoString hostACE;
     679               1 :     if (idn && !IsASCII(hostname)) {
     680               0 :         if (NS_SUCCEEDED(idn->ConvertUTF8toACE(hostname, hostACE)))
     681               0 :             hostPtr = &hostACE;
     682                 :     }
     683                 : 
     684                 :     //
     685                 :     // sync resolve: since the host resolver only works asynchronously, we need
     686                 :     // to use a mutex and a condvar to wait for the result.  however, since the
     687                 :     // result may be in the resolvers cache, we might get called back recursively
     688                 :     // on the same thread.  so, our mutex needs to be re-entrant.  in other words,
     689                 :     // we need to use a monitor! ;-)
     690                 :     //
     691                 :     
     692               1 :     PRMonitor *mon = PR_NewMonitor();
     693               1 :     if (!mon)
     694               0 :         return NS_ERROR_OUT_OF_MEMORY;
     695                 : 
     696               1 :     PR_EnterMonitor(mon);
     697               2 :     nsDNSSyncRequest syncReq(mon);
     698                 : 
     699               1 :     PRUint16 af = GetAFForLookup(*hostPtr, flags);
     700                 : 
     701               1 :     rv = res->ResolveHost(PromiseFlatCString(*hostPtr).get(), flags, af, &syncReq);
     702               1 :     if (NS_SUCCEEDED(rv)) {
     703                 :         // wait for result
     704               3 :         while (!syncReq.mDone)
     705               1 :             PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT);
     706                 : 
     707               1 :         if (NS_FAILED(syncReq.mStatus))
     708               0 :             rv = syncReq.mStatus;
     709                 :         else {
     710               1 :             NS_ASSERTION(syncReq.mHostRecord, "no host record");
     711               2 :             nsDNSRecord *rec = new nsDNSRecord(syncReq.mHostRecord);
     712               1 :             if (!rec)
     713               0 :                 rv = NS_ERROR_OUT_OF_MEMORY;
     714                 :             else
     715               1 :                 NS_ADDREF(*result = rec);
     716                 :         }
     717                 :     }
     718                 : 
     719               1 :     PR_ExitMonitor(mon);
     720               1 :     PR_DestroyMonitor(mon);
     721               1 :     return rv;
     722                 : }
     723                 : 
     724                 : NS_IMETHODIMP
     725               0 : nsDNSService::GetMyHostName(nsACString &result)
     726                 : {
     727                 :     char name[100];
     728               0 :     if (PR_GetSystemInfo(PR_SI_HOSTNAME, name, sizeof(name)) == PR_SUCCESS) {
     729               0 :         result = name;
     730               0 :         return NS_OK;
     731                 :     }
     732               0 :     return NS_ERROR_FAILURE;
     733                 : }
     734                 : 
     735                 : NS_IMETHODIMP
     736              18 : nsDNSService::Observe(nsISupports *subject, const char *topic, const PRUnichar *data)
     737                 : {
     738                 :     // we are only getting called if a preference has changed. 
     739              18 :     NS_ASSERTION(strcmp(topic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0,
     740                 :         "unexpected observe call");
     741                 : 
     742                 :     //
     743                 :     // Shutdown and this function are both only called on the UI thread, so we don't
     744                 :     // have to worry about mResolver being cleared out from under us.
     745                 :     //
     746                 :     // NOTE Shutting down and reinitializing the service like this is obviously
     747                 :     // suboptimal if Observe gets called several times in a row, but we don't
     748                 :     // expect that to be the case.
     749                 :     //
     750                 : 
     751              18 :     if (mResolver) {
     752              18 :         Shutdown();
     753                 :     }
     754              18 :     Init();
     755              18 :     return NS_OK;
     756                 : }
     757                 : 
     758                 : PRUint16
     759            6493 : nsDNSService::GetAFForLookup(const nsACString &host, PRUint32 flags)
     760                 : {
     761            6493 :     if (mDisableIPv6 || (flags & RESOLVE_DISABLE_IPV6))
     762               0 :         return PR_AF_INET;
     763                 : 
     764           12986 :     MutexAutoLock lock(mLock);
     765                 : 
     766            6493 :     PRUint16 af = PR_AF_UNSPEC;
     767                 : 
     768            6493 :     if (!mIPv4OnlyDomains.IsEmpty()) {
     769                 :         const char *domain, *domainEnd, *end;
     770                 :         PRUint32 hostLen, domainLen;
     771                 : 
     772                 :         // see if host is in one of the IPv4-only domains
     773               0 :         domain = mIPv4OnlyDomains.BeginReading();
     774               0 :         domainEnd = mIPv4OnlyDomains.EndReading(); 
     775                 : 
     776               0 :         nsACString::const_iterator hostStart;
     777               0 :         host.BeginReading(hostStart);
     778               0 :         hostLen = host.Length();
     779                 : 
     780               0 :         do {
     781                 :             // skip any whitespace
     782               0 :             while (*domain == ' ' || *domain == '\t')
     783               0 :                 ++domain;
     784                 : 
     785                 :             // find end of this domain in the string
     786               0 :             end = strchr(domain, ',');
     787               0 :             if (!end)
     788               0 :                 end = domainEnd;
     789                 : 
     790                 :             // to see if the hostname is in the domain, check if the domain
     791                 :             // matches the end of the hostname.
     792               0 :             domainLen = end - domain;
     793               0 :             if (domainLen && hostLen >= domainLen) {
     794               0 :                 const char *hostTail = hostStart.get() + hostLen - domainLen;
     795               0 :                 if (PL_strncasecmp(domain, hostTail, domainLen) == 0) {
     796                 :                     // now, make sure either that the hostname is a direct match or
     797                 :                     // that the hostname begins with a dot.
     798               0 :                     if (hostLen == domainLen ||
     799               0 :                             *hostTail == '.' || *(hostTail - 1) == '.') {
     800               0 :                         af = PR_AF_INET;
     801               0 :                         break;
     802                 :                     }
     803                 :                 }
     804                 :             }
     805                 : 
     806               0 :             domain = end + 1;
     807                 :         } while (*end);
     808                 :     }
     809                 : 
     810            6493 :     return af;
     811                 : }

Generated by: LCOV version 1.7