// Returns the number of entries processed int CAddrMan::CopyDestinationStats( std::vector<CDestinationStats>& vStats ) { int nSize = 0; vStats.clear(); vStats.reserve( mapI2pHashes.size() ); for( std::map<uint256, int>::iterator it = mapI2pHashes.begin(); it != mapI2pHashes.end(); it++) { CDestinationStats stats; std::map<int, CAddrInfo>::iterator it2 = mapInfo.find((*it).second); if (it2 != mapInfo.end()) { CAddrInfo* paddr = &(*it2).second; stats.sAddress = paddr->ToString(); stats.fInTried = paddr->fInTried; stats.uPort = paddr->GetPort(); stats.nServices = paddr->nServices; stats.nAttempts = paddr->nAttempts; stats.nLastTry = paddr->nLastTry; stats.nSuccessTime = paddr->nLastSuccess; stats.sSource = paddr->source.ToString(); stats.sBase64 = paddr->GetI2pDestination(); nSize++; vStats.push_back( stats ); } } assert( mapI2pHashes.size() == nSize ); return nSize; }
bool CAddrMan::Add_(const CAddress &addr, const CNetAddr& source, int64_t nTimePenalty) { if (!addr.IsRoutable()) return false; bool fNew = false; int nId; CAddrInfo *pinfo = Find(addr, &nId); if (pinfo) { // periodically update nTime bool fCurrentlyOnline = (GetAdjustedTime() - addr.nTime < 24 * 60 * 60); int64_t nUpdateInterval = (fCurrentlyOnline ? 60 * 60 : 24 * 60 * 60); if (addr.nTime && (!pinfo->nTime || pinfo->nTime < addr.nTime - nUpdateInterval - nTimePenalty)) pinfo->nTime = max((int64_t)0, addr.nTime - nTimePenalty); // add services pinfo->nServices |= addr.nServices; // do not update if no new information is present if (!addr.nTime || (pinfo->nTime && addr.nTime <= pinfo->nTime)) return false; // do not update if the entry was already in the "tried" table if (pinfo->fInTried) return false; // do not update if the max reference count is reached if (pinfo->nRefCount == ADDRMAN_NEW_BUCKETS_PER_ADDRESS) return false; // stochastic test: previous nRefCount == N: 2^N times harder to increase it int nFactor = 1; for (int n=0; n<pinfo->nRefCount; n++) nFactor *= 2; if (nFactor > 1 && (GetRandInt(nFactor) != 0)) return false; } else { pinfo = Create(addr, source, &nId); pinfo->nTime = max((int64_t)0, (int64_t)pinfo->nTime - nTimePenalty); // printf("Added %s [nTime=%fhr]\n", pinfo->ToString().c_str(), (GetAdjustedTime() - pinfo->nTime) / 3600.0); nNew++; fNew = true; } int nUBucket = pinfo->GetNewBucket(nKey, source); std::set<int> &vNew = vvNew[nUBucket]; if (!vNew.count(nId)) { pinfo->nRefCount++; if (vNew.size() == ADDRMAN_NEW_BUCKET_SIZE) ShrinkNew(nUBucket); vvNew[nUBucket].insert(nId); } return fNew; }
bool CAddrMan::Add_(const CAddress &addr, const CNetAddr& source, int64 nTimePenalty) { if (!addr.IsRoutable()) return false; bool fNew = false; int nId; CAddrInfo *pinfo = Find(addr, &nId); if (pinfo) { // periodically update nTime периодически обновлять Ntime bool fCurrentlyOnline = (GetAdjustedTime() - addr.nTime < 24 * 60 * 60); int64 nUpdateInterval = (fCurrentlyOnline ? 60 * 60 : 24 * 60 * 60); if (addr.nTime && (!pinfo->nTime || pinfo->nTime < addr.nTime - nUpdateInterval - nTimePenalty)) pinfo->nTime = max((int64)0, addr.nTime - nTimePenalty); // add services добаление сервисов pinfo->nServices |= addr.nServices; // do not update if no new information is present не обновлять, если никакой новой информации не присутствует if (!addr.nTime || (pinfo->nTime && addr.nTime <= pinfo->nTime)) return false; // do not update if the entry was already in the "tried" table не обновлять, если запись уже была в таблицы "проверенных" if (pinfo->fInTried) return false; // do not update if the max reference count is reached не обновлять, если достигнут максимум счетчика ссылок if (pinfo->nRefCount == ADDRMAN_NEW_BUCKETS_PER_ADDRESS) return false; // stochastic test: previous nRefCount == N: 2^N times harder to increase it(2^N раз сложнее его увеличить) int nFactor = 1; for (int n=0; n<pinfo->nRefCount; n++) nFactor *= 2; if (nFactor > 1 && (GetRandInt(nFactor) != 0)) return false; } else { pinfo = Create(addr, source, &nId); pinfo->nTime = max((int64)0, (int64)pinfo->nTime - nTimePenalty); // printf("Added %s [nTime=%fhr]\n", pinfo->ToString().c_str(), (GetAdjustedTime() - pinfo->nTime) / 3600.0); nNew++; fNew = true; } int nUBucket = pinfo->GetNewBucket(nKey, source); std::set<int> &vNew = vvNew[nUBucket]; if (!vNew.count(nId)) { pinfo->nRefCount++; if (vNew.size() == ADDRMAN_NEW_BUCKET_SIZE) ShrinkNew(nUBucket); vvNew[nUBucket].insert(nId); } return fNew; }
void CAddrMan::MakeTried(CAddrInfo& info, int nId) { // remove the entry from all new buckets for (int bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) { int pos = info.GetBucketPosition(nKey, true, bucket); if (vvNew[bucket][pos] == nId) { vvNew[bucket][pos] = -1; info.nRefCount--; } } nNew--; assert(info.nRefCount == 0); // which tried bucket to move the entry to int nKBucket = info.GetTriedBucket(nKey); int nKBucketPos = info.GetBucketPosition(nKey, false, nKBucket); // first make space to add it (the existing tried entry there is moved to new, deleting whatever is there). if (vvTried[nKBucket][nKBucketPos] != -1) { // find an item to evict int nIdEvict = vvTried[nKBucket][nKBucketPos]; assert(mapInfo.count(nIdEvict) == 1); CAddrInfo& infoOld = mapInfo[nIdEvict]; // Remove the to-be-evicted item from the tried set. infoOld.fInTried = false; vvTried[nKBucket][nKBucketPos] = -1; nTried--; // find which new bucket it belongs to int nUBucket = infoOld.GetNewBucket(nKey); int nUBucketPos = infoOld.GetBucketPosition(nKey, true, nUBucket); ClearNew(nUBucket, nUBucketPos); assert(vvNew[nUBucket][nUBucketPos] == -1); // Enter it into the new set again. infoOld.nRefCount = 1; vvNew[nUBucket][nUBucketPos] = nIdEvict; nNew++; } assert(vvTried[nKBucket][nKBucketPos] == -1); vvTried[nKBucket][nKBucketPos] = nId; nTried++; info.fInTried = true; }
void CAddrMan::MakeTried(CAddrInfo& info, int nId, int nOrigin) { assert(vvNew[nOrigin].count(nId) == 1); // remove the entry from all new buckets for (std::vector<std::set<int> >::iterator it = vvNew.begin(); it != vvNew.end(); it++) { if ((*it).erase(nId)) info.nRefCount--; } nNew--; assert(info.nRefCount == 0); // what tried bucket to move the entry to int nKBucket = info.GetTriedBucket(nKey); std::vector<int> &vTried = vvTried[nKBucket]; // first check whether there is place to just add it if (vTried.size() < ADDRMAN_TRIED_BUCKET_SIZE) { vTried.push_back(nId); nTried++; info.fInTried = true; return; } // otherwise, find an item to evict int nPos = SelectTried(nKBucket); // find which new bucket it belongs to assert(mapInfo.count(vTried[nPos]) == 1); int nUBucket = mapInfo[vTried[nPos]].GetNewBucket(nKey); std::set<int> &vNew = vvNew[nUBucket]; // remove the to-be-replaced tried entry from the tried set CAddrInfo& infoOld = mapInfo[vTried[nPos]]; infoOld.fInTried = false; infoOld.nRefCount = 1; // do not update nTried, as we are going to move something else there immediately // check whether there is place in that one, if (vNew.size() < ADDRMAN_NEW_BUCKET_SIZE) { // if so, move it back there vNew.insert(vTried[nPos]); } else { // otherwise, move it to the new bucket nId came from (there is certainly place there) vvNew[nOrigin].insert(vTried[nPos]); } nNew++; vTried[nPos] = nId; // we just overwrote an entry in vTried; no need to update nTried info.fInTried = true; return; }
void CAddrMan::MakeTried(CAddrInfo& info, int nId, int nOrigin) { assert(vvNew[nOrigin].count(nId) == 1); // remove the entry from all new buckets удаление записей из всех новых бакетов for (std::vector<std::set<int> >::iterator it = vvNew.begin(); it != vvNew.end(); it++) { if ((*it).erase(nId)) info.nRefCount--; } nNew--; assert(info.nRefCount == 0); // what tried bucket to move the entry to что пытались бакет для перемещения записи int nKBucket = info.GetTriedBucket(nKey); std::vector<int> &vTried = vvTried[nKBucket]; // first check whether there is place to just add it сначала проверьте, есть ли место, чтобы просто добавить его if (vTried.size() < ADDRMAN_TRIED_BUCKET_SIZE) { vTried.push_back(nId); nTried++; info.fInTried = true; return; } // otherwise, find an item to evict в противном случае, найти пункт, чтобы выселить int nPos = SelectTried(nKBucket); // find which new bucket it belongs to найти, к какому новому бакету он принадлежит assert(mapInfo.count(vTried[nPos]) == 1); int nUBucket = mapInfo[vTried[nPos]].GetNewBucket(nKey); std::set<int> &vNew = vvNew[nUBucket]; // remove the to-be-replaced tried entry from the tried set удаление быть-замененой проверенную запись из проверяемого набора CAddrInfo& infoOld = mapInfo[vTried[nPos]]; infoOld.fInTried = false; infoOld.nRefCount = 1; // do not update nTried, as we are going to move something else there immediately не модернизирорать nTried, поскольку мы собираемся перемещать что-то еще туда немедленно // check whether there is place in that one, проверьте, есть ли место для одного if (vNew.size() < ADDRMAN_NEW_BUCKET_SIZE) { // if so, move it back there если это так, переместить его туда vNew.insert(vTried[nPos]); } else { // otherwise, move it to the new bucket nId came from (there is certainly place there) иначе, переместить его в новый бакет nId (безусловно есть там) vvNew[nOrigin].insert(vTried[nPos]); } nNew++; vTried[nPos] = nId; // we just overwrote an entry in vTried; no need to update nTried мы просто переписываем запись в vTried, не нужно обновлять nTried info.fInTried = true; return; }
void CAddrMan::MakeTried(CAddrInfo& info, int nId) { for (int bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) { int pos = info.GetBucketPosition(nKey, true, bucket); if (vvNew[bucket][pos] == nId) { vvNew[bucket][pos] = -1; info.nRefCount--; } } nNew--; assert(info.nRefCount == 0); int nKBucket = info.GetTriedBucket(nKey); int nKBucketPos = info.GetBucketPosition(nKey, false, nKBucket); if (vvTried[nKBucket][nKBucketPos] != -1) { int nIdEvict = vvTried[nKBucket][nKBucketPos]; assert(mapInfo.count(nIdEvict) == 1); CAddrInfo& infoOld = mapInfo[nIdEvict]; infoOld.fInTried = false; vvTried[nKBucket][nKBucketPos] = -1; nTried--; int nUBucket = infoOld.GetNewBucket(nKey); int nUBucketPos = infoOld.GetBucketPosition(nKey, true, nUBucket); ClearNew(nUBucket, nUBucketPos); assert(vvNew[nUBucket][nUBucketPos] == -1); infoOld.nRefCount = 1; vvNew[nUBucket][nUBucketPos] = nIdEvict; nNew++; } assert(vvTried[nKBucket][nKBucketPos] == -1); vvTried[nKBucket][nKBucketPos] = nId; nTried++; info.fInTried = true; }
void CAddrMan::CheckAndDeleteB32Hash( const int nID, const CAddrInfo& aTerrible ) { if( aTerrible.IsI2P() ) { uint256 b32hash = GetI2pDestinationHash( aTerrible.GetI2pDestination() ); if( mapI2pHashes.count( b32hash ) == 1 ) { int nID2 = mapI2pHashes[ b32hash ]; if( nID == nID2 ) // Yap this is the one they want to delete, and it exists mapI2pHashes.erase( b32hash ); else { LogPrint( "addrman", "While attempting to erase base32 hash %s, it was unexpected that the ids differ id1=%d != id2=%d\n", b32hash.GetHex(), nID, nID2 ); // CAddrInfo& info2 = mapInfo[nID2]; // aTerrible.print(); // info2.print(); } } else { LogPrint( "addrman", "While attempting to remove base32 hash %s, it was found to not exist.\n", b32hash.GetHex() ); // aTerrible.print(); } } }
bool CAddrMan::Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimePenalty) { if (!addr.IsRoutable()) return false; bool fNew = false; int nId; CAddrInfo* pinfo = Find(addr, &nId); if (pinfo) { // periodically update nTime bool fCurrentlyOnline = (GetAdjustedTime() - addr.nTime < 24 * 60 * 60); int64_t nUpdateInterval = (fCurrentlyOnline ? 60 * 60 : 24 * 60 * 60); if (addr.nTime && (!pinfo->nTime || pinfo->nTime < addr.nTime - nUpdateInterval - nTimePenalty)) pinfo->nTime = max((int64_t)0, addr.nTime - nTimePenalty); // add services pinfo->nServices |= addr.nServices; // do not update if no new information is present if (!addr.nTime || (pinfo->nTime && addr.nTime <= pinfo->nTime)) return false; // do not update if the entry was already in the "tried" table if (pinfo->fInTried) return false; // do not update if the max reference count is reached if (pinfo->nRefCount == ADDRMAN_NEW_BUCKETS_PER_ADDRESS) return false; // stochastic test: previous nRefCount == N: 2^N times harder to increase it int nFactor = 1; for (int n = 0; n < pinfo->nRefCount; n++) nFactor *= 2; if (nFactor > 1 && (GetRandInt(nFactor) != 0)) return false; } else { pinfo = Create(addr, source, &nId); pinfo->nTime = max((int64_t)0, (int64_t)pinfo->nTime - nTimePenalty); nNew++; fNew = true; } int nUBucket = pinfo->GetNewBucket(nKey, source); int nUBucketPos = pinfo->GetBucketPosition(nKey, true, nUBucket); if (vvNew[nUBucket][nUBucketPos] != nId) { bool fInsert = vvNew[nUBucket][nUBucketPos] == -1; if (!fInsert) { CAddrInfo& infoExisting = mapInfo[vvNew[nUBucket][nUBucketPos]]; if (infoExisting.IsTerrible() || (infoExisting.nRefCount > 1 && pinfo->nRefCount == 0)) { // Overwrite the existing new table entry. fInsert = true; } } if (fInsert) { ClearNew(nUBucket, nUBucketPos); pinfo->nRefCount++; vvNew[nUBucket][nUBucketPos] = nId; } else { if (pinfo->nRefCount == 0) { Delete(nId); } } } return fNew; }
bool CAddrMan::Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimePenalty) { if (!addr.IsRoutable()) return false; bool fNew = false; int nId; CAddrInfo* pinfo = Find(addr, &nId); if (pinfo) { bool fCurrentlyOnline = (GetAdjustedTime() - addr.nTime < 24 * 60 * 60); int64_t nUpdateInterval = (fCurrentlyOnline ? 60 * 60 : 24 * 60 * 60); if (addr.nTime && (!pinfo->nTime || pinfo->nTime < addr.nTime - nUpdateInterval - nTimePenalty)) pinfo->nTime = std::max((int64_t)0, addr.nTime - nTimePenalty); pinfo->nServices = ServiceFlags(pinfo->nServices | addr.nServices); if (!addr.nTime || (pinfo->nTime && addr.nTime <= pinfo->nTime)) return false; if (pinfo->fInTried) return false; if (pinfo->nRefCount == ADDRMAN_NEW_BUCKETS_PER_ADDRESS) return false; int nFactor = 1; for (int n = 0; n < pinfo->nRefCount; n++) nFactor *= 2; if (nFactor > 1 && (RandomInt(nFactor) != 0)) return false; } else { pinfo = Create(addr, source, &nId); pinfo->nTime = std::max((int64_t)0, (int64_t)pinfo->nTime - nTimePenalty); nNew++; fNew = true; } int nUBucket = pinfo->GetNewBucket(nKey, source); int nUBucketPos = pinfo->GetBucketPosition(nKey, true, nUBucket); if (vvNew[nUBucket][nUBucketPos] != nId) { bool fInsert = vvNew[nUBucket][nUBucketPos] == -1; if (!fInsert) { CAddrInfo& infoExisting = mapInfo[vvNew[nUBucket][nUBucketPos]]; if (infoExisting.IsTerrible() || (infoExisting.nRefCount > 1 && pinfo->nRefCount == 0)) { fInsert = true; } } if (fInsert) { ClearNew(nUBucket, nUBucketPos); pinfo->nRefCount++; vvNew[nUBucket][nUBucketPos] = nId; } else { if (pinfo->nRefCount == 0) { Delete(nId); } } } return fNew; }
bool CAddrMan::Add_(const CAddress& addrIn, const CNetAddr& source, int64_t nTimePenalty) { #ifdef I2PADDRMAN_EXTENSIONS //! We now need to check for an possibly modify the CAddress object for the garliccat field, so we make a local copy CAddress addr = addrIn; /** * Before we can add an address, even before we can test if its Routable, or use the Find command to match correctly, * we need to make sure that any I2P addresses have the GarlicCat field setup correctly in the IP area of the * CNetAddr portion of a given CAddress->CService->CNetAddr object, this should have already been done, but * double checking it here also insures we do not get a polluted b32 hash map */ if( addr.CheckAndSetGarlicCat() ) LogPrint( "addrman", "While adding an i2p destination, did not expect to need the garliccat fixed for %s\n", addr.ToString() ); #endif if( !addr.IsRoutable() ) { LogPrint( "addrman", "While adding an address, did not expect to find it unroutable: %s\n", addr.ToString() ); return false; } bool fNew = false; int nId; /** * Find Matches by CNetAddr objects, and returns the CAddrInfo object it finds, which is fine and what we want normally * however this means the ports can be different (CService), and other details in the CAddress portion, such as nServices * should not simply be 'or'd with what was found, sometimes we have to remove services in the version exchange that * peers report incorrectly, and having the port wrong means when Good_ is called that the objects do not match exactly. */ CAddrInfo* pinfo = Find(addr, &nId); if (pinfo) { // periodically update nTime bool fCurrentlyOnline = (GetAdjustedTime() - addr.nTime < 24 * 60 * 60); int64_t nUpdateInterval = (fCurrentlyOnline ? 60 * 60 : 24 * 60 * 60); if (addr.nTime && (!pinfo->nTime || pinfo->nTime < addr.nTime - nUpdateInterval - nTimePenalty)) pinfo->nTime = std::max((int64_t)0, addr.nTime - nTimePenalty); /** * Only do the following, IF the source of this information is the node itself (source), * otherwise we're just constantly changing the details, while getting addresses from peers. * * The call (to addrman.Add()) which puts us here, happens at the end of a version message exchange, * for inbound connections only. * For outbound connections, we only have a call to good, if the connection is made. * Other places addrman.Add() is called is for address seeding and user lookup, see net.cpp for those details */ if( (CNetAddr)addr == source ) { /** * add services, don't just 'or' them in here, hard set them to the correct value * original code: pinfo->nServices |= addr.nServices; * ToDo: Why this and the port value has not been fixed as standard procedure could be investigated in more detail * for now Anoncoin has so many unique problems with these 2 values, this should help correct allot of the * current network issues in regard to the values getting corrected over time. */ if( pinfo->nServices != addr.nServices ) { LogPrint( "addrman", "Updating peer record %s, the services listed needed to be changed. From 0x%016x To 0x%016x\n", pinfo->ToString(), pinfo->nServices, addr.nServices ); pinfo->nServices = addr.nServices; } if( pinfo->GetPort() != addr.GetPort() ) { LogPrint( "addrman", "Updating peer record %s, port %d was wrong, changed it to %d\n", pinfo->ToString(), pinfo->GetPort(), addr.GetPort() ); pinfo->SetPort( addr.GetPort() ); } } // do not update if no new information is present if (!addr.nTime || (pinfo->nTime && addr.nTime <= pinfo->nTime)) return false; // do not update if the entry was already in the "tried" table if (pinfo->fInTried) return false; // do not update if the max reference count is reached if (pinfo->nRefCount == ADDRMAN_NEW_BUCKETS_PER_ADDRESS) return false; // stochastic test: previous nRefCount == N: 2^N times harder to increase it int nFactor = 1; for (int n = 0; n < pinfo->nRefCount; n++) nFactor *= 2; if (nFactor > 1 && (GetRandInt(nFactor) != 0)) return false; } else { pinfo = Create(addr, source, &nId); pinfo->nTime = std::max((int64_t)0, (int64_t)pinfo->nTime - nTimePenalty); nNew++; fNew = true; } int nUBucket = pinfo->GetNewBucket(nKey, source); int nUBucketPos = pinfo->GetBucketPosition(nKey, true, nUBucket); if (vvNew[nUBucket][nUBucketPos] != nId) { bool fInsert = vvNew[nUBucket][nUBucketPos] == -1; if (!fInsert) { CAddrInfo& infoExisting = mapInfo[vvNew[nUBucket][nUBucketPos]]; if (infoExisting.IsTerrible() || (infoExisting.nRefCount > 1 && pinfo->nRefCount == 0)) { // Overwrite the existing new table entry. fInsert = true; } } if (fInsert) { ClearNew(nUBucket, nUBucketPos); pinfo->nRefCount++; vvNew[nUBucket][nUBucketPos] = nId; } else { if (pinfo->nRefCount == 0) { Delete(nId); } } } return fNew; }
/** \brief Simply looks up the hash, if the id is found returns a pointer to the CAddrInfo(CAddress(CService(CNetAddr()))) class object where the base64 string is stored * * \param sB32addr const string& * \return string, null if not found or the Base64 destination string of give b32.i2p address * */ std::string CAddrMan::GetI2pBase64Destination(const std::string& sB32addr) { CAddrInfo* paddr = LookupB32addr(sB32addr); return paddr && paddr->IsI2P() ? paddr->GetI2pDestination() : std::string(); }