NS_IMETHODIMP nsDNSRecord::GetAddresses(nsTArray<NetAddr> & aAddressArray) { if (mDone) { return NS_ERROR_NOT_AVAILABLE; } mHostRecord->addr_info_lock.Lock(); if (mHostRecord->addr_info) { for (NetAddrElement *iter = mHostRecord->addr_info->mAddresses.getFirst(); iter; iter = iter->getNext()) { if (mHostRecord->Blacklisted(&iter->mAddress)) { continue; } NetAddr *addr = aAddressArray.AppendElement(NetAddr()); memcpy(addr, &iter->mAddress, sizeof(NetAddr)); if (addr->raw.family == AF_INET) { addr->inet.port = 0; } else if (addr->raw.family == AF_INET6) { addr->inet6.port = 0; } } mHostRecord->addr_info_lock.Unlock(); } else { mHostRecord->addr_info_lock.Unlock(); if (!mHostRecord->addr) { return NS_ERROR_NOT_AVAILABLE; } NetAddr *addr = aAddressArray.AppendElement(NetAddr()); memcpy(addr, mHostRecord->addr, sizeof(NetAddr)); if (addr->raw.family == AF_INET) { addr->inet.port = 0; } else if (addr->raw.family == AF_INET6) { addr->inet6.port = 0; } } return NS_OK; }
NS_IMETHODIMP nsDNSRecord::GetNextAddr(PRUint16 port, PRNetAddr *addr) { // not a programming error to poke the DNS record when it has no more // entries. just fail without any debug warnings. this enables consumers // to enumerate the DNS record without calling HasMore. if (mDone) return NS_ERROR_NOT_AVAILABLE; mHostRecord->addr_info_lock.Lock(); bool startedFresh = !mIter; if (mHostRecord->addr_info) { if (!mIter) mIterGenCnt = mHostRecord->addr_info_gencnt; else if (mIterGenCnt != mHostRecord->addr_info_gencnt) { // mHostRecord->addr_info has changed, so mIter is invalid. // Restart the iteration. Alternatively, we could just fail. mIter = nsnull; mIterGenCnt = mHostRecord->addr_info_gencnt; startedFresh = true; } do { mLastIter = mIter; mIter = PR_EnumerateAddrInfo(mIter, mHostRecord->addr_info, port, addr); } while (mIter && mHostRecord->Blacklisted(addr)); if (startedFresh && !mIter) { // if everything was blacklisted we want to reset the blacklist (and // likely relearn it) and return the first address. That is better // than nothing mHostRecord->ResetBlacklist(); mLastIter = nsnull; mIter = PR_EnumerateAddrInfo(nsnull, mHostRecord->addr_info, port, addr); } mHostRecord->addr_info_lock.Unlock(); if (!mIter) { mDone = true; return NS_ERROR_NOT_AVAILABLE; } } else { mHostRecord->addr_info_lock.Unlock(); if (!mHostRecord->addr) { // Both mHostRecord->addr_info and mHostRecord->addr are null. // This can happen if mHostRecord->addr_info expired and the // attempt to reresolve it failed. return NS_ERROR_NOT_AVAILABLE; } memcpy(addr, mHostRecord->addr, sizeof(PRNetAddr)); // set given port port = PR_htons(port); if (addr->raw.family == PR_AF_INET) addr->inet.port = port; else addr->ipv6.port = port; mDone = true; // no iterations } return NS_OK; }
NS_IMETHODIMP nsDNSRecord::GetNextAddr(uint16_t port, NetAddr *addr) { if (mDone) { return NS_ERROR_NOT_AVAILABLE; } mHostRecord->addr_info_lock.Lock(); if (mHostRecord->addr_info) { if (mIterGenCnt != mHostRecord->addr_info_gencnt) { // mHostRecord->addr_info has changed, restart the iteration. mIter = nullptr; mIterGenCnt = mHostRecord->addr_info_gencnt; } bool startedFresh = !mIter; do { if (!mIter) { mIter = mHostRecord->addr_info->mAddresses.getFirst(); } else { mIter = mIter->getNext(); } } while (mIter && mHostRecord->Blacklisted(&mIter->mAddress)); if (!mIter && startedFresh) { // If everything was blacklisted we want to reset the blacklist (and // likely relearn it) and return the first address. That is better // than nothing. mHostRecord->ResetBlacklist(); mIter = mHostRecord->addr_info->mAddresses.getFirst(); } if (mIter) { memcpy(addr, &mIter->mAddress, sizeof(NetAddr)); } mHostRecord->addr_info_lock.Unlock(); if (!mIter) { mDone = true; return NS_ERROR_NOT_AVAILABLE; } } else { mHostRecord->addr_info_lock.Unlock(); if (!mHostRecord->addr) { // Both mHostRecord->addr_info and mHostRecord->addr are null. // This can happen if mHostRecord->addr_info expired and the // attempt to reresolve it failed. return NS_ERROR_NOT_AVAILABLE; } memcpy(addr, mHostRecord->addr, sizeof(NetAddr)); mDone = true; } // set given port port = htons(port); if (addr->raw.family == AF_INET) { addr->inet.port = port; } else if (addr->raw.family == AF_INET6) { addr->inet6.port = port; } return NS_OK; }