]>
Commit | Line | Data |
---|---|---|
5fee401f PW |
1 | // Copyright (c) 2012 Pieter Wuille |
2 | // Distributed under the MIT/X11 software license, see the accompanying | |
3a25a2b9 | 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. |
5fee401f PW |
4 | |
5 | #include "addrman.h" | |
51ed9ec9 | 6 | |
0fb9073e | 7 | #include "hash.h" |
51ed9ec9 | 8 | #include "serialize.h" |
fa736190 | 9 | #include "streams.h" |
5fee401f PW |
10 | |
11 | using namespace std; | |
12 | ||
20e01b1a | 13 | int CAddrInfo::GetTriedBucket(const std::vector<unsigned char>& nKey) const |
5fee401f | 14 | { |
6b6aaa16 | 15 | CDataStream ss1(SER_GETHASH, 0); |
5fee401f PW |
16 | std::vector<unsigned char> vchKey = GetKey(); |
17 | ss1 << nKey << vchKey; | |
e85e19be | 18 | uint64_t hash1 = Hash(ss1.begin(), ss1.end()).GetLow64(); |
5fee401f | 19 | |
6b6aaa16 | 20 | CDataStream ss2(SER_GETHASH, 0); |
5fee401f PW |
21 | std::vector<unsigned char> vchGroupKey = GetGroup(); |
22 | ss2 << nKey << vchGroupKey << (hash1 % ADDRMAN_TRIED_BUCKETS_PER_GROUP); | |
e85e19be | 23 | uint64_t hash2 = Hash(ss2.begin(), ss2.end()).GetLow64(); |
5fee401f PW |
24 | return hash2 % ADDRMAN_TRIED_BUCKET_COUNT; |
25 | } | |
26 | ||
20e01b1a | 27 | int CAddrInfo::GetNewBucket(const std::vector<unsigned char>& nKey, const CNetAddr& src) const |
5fee401f | 28 | { |
6b6aaa16 | 29 | CDataStream ss1(SER_GETHASH, 0); |
5fee401f PW |
30 | std::vector<unsigned char> vchGroupKey = GetGroup(); |
31 | std::vector<unsigned char> vchSourceGroupKey = src.GetGroup(); | |
32 | ss1 << nKey << vchGroupKey << vchSourceGroupKey; | |
e85e19be | 33 | uint64_t hash1 = Hash(ss1.begin(), ss1.end()).GetLow64(); |
5fee401f | 34 | |
6b6aaa16 | 35 | CDataStream ss2(SER_GETHASH, 0); |
5fee401f | 36 | ss2 << nKey << vchSourceGroupKey << (hash1 % ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP); |
e85e19be | 37 | uint64_t hash2 = Hash(ss2.begin(), ss2.end()).GetLow64(); |
5fee401f PW |
38 | return hash2 % ADDRMAN_NEW_BUCKET_COUNT; |
39 | } | |
40 | ||
51ed9ec9 | 41 | bool CAddrInfo::IsTerrible(int64_t nNow) const |
5fee401f | 42 | { |
20e01b1a | 43 | if (nLastTry && nLastTry >= nNow - 60) // never remove things tried the last minute |
5fee401f PW |
44 | return false; |
45 | ||
20e01b1a | 46 | if (nTime > nNow + 10 * 60) // came in a flying DeLorean |
5fee401f PW |
47 | return true; |
48 | ||
20e01b1a | 49 | if (nTime == 0 || nNow - nTime > ADDRMAN_HORIZON_DAYS * 24 * 60 * 60) // not seen in recent history |
5fee401f PW |
50 | return true; |
51 | ||
20e01b1a | 52 | if (nLastSuccess == 0 && nAttempts >= ADDRMAN_RETRIES) // tried N times and never a success |
5fee401f PW |
53 | return true; |
54 | ||
20e01b1a | 55 | if (nNow - nLastSuccess > ADDRMAN_MIN_FAIL_DAYS * 24 * 60 * 60 && nAttempts >= ADDRMAN_MAX_FAILURES) // N successive failures in the last week |
5fee401f PW |
56 | return true; |
57 | ||
58 | return false; | |
59 | } | |
60 | ||
51ed9ec9 | 61 | double CAddrInfo::GetChance(int64_t nNow) const |
5fee401f PW |
62 | { |
63 | double fChance = 1.0; | |
64 | ||
51ed9ec9 BD |
65 | int64_t nSinceLastSeen = nNow - nTime; |
66 | int64_t nSinceLastTry = nNow - nLastTry; | |
5fee401f | 67 | |
20e01b1a PW |
68 | if (nSinceLastSeen < 0) |
69 | nSinceLastSeen = 0; | |
70 | if (nSinceLastTry < 0) | |
71 | nSinceLastTry = 0; | |
5fee401f PW |
72 | |
73 | fChance *= 600.0 / (600.0 + nSinceLastSeen); | |
74 | ||
75 | // deprioritize very recent attempts away | |
20e01b1a | 76 | if (nSinceLastTry < 60 * 10) |
5fee401f PW |
77 | fChance *= 0.01; |
78 | ||
79 | // deprioritize 50% after each failed attempt | |
20e01b1a | 80 | for (int n = 0; n < nAttempts; n++) |
5fee401f PW |
81 | fChance /= 1.5; |
82 | ||
83 | return fChance; | |
84 | } | |
85 | ||
20e01b1a | 86 | CAddrInfo* CAddrMan::Find(const CNetAddr& addr, int* pnId) |
5fee401f PW |
87 | { |
88 | std::map<CNetAddr, int>::iterator it = mapAddr.find(addr); | |
89 | if (it == mapAddr.end()) | |
90 | return NULL; | |
91 | if (pnId) | |
92 | *pnId = (*it).second; | |
93 | std::map<int, CAddrInfo>::iterator it2 = mapInfo.find((*it).second); | |
94 | if (it2 != mapInfo.end()) | |
95 | return &(*it2).second; | |
96 | return NULL; | |
97 | } | |
98 | ||
20e01b1a | 99 | CAddrInfo* CAddrMan::Create(const CAddress& addr, const CNetAddr& addrSource, int* pnId) |
5fee401f PW |
100 | { |
101 | int nId = nIdCount++; | |
102 | mapInfo[nId] = CAddrInfo(addr, addrSource); | |
103 | mapAddr[addr] = nId; | |
104 | mapInfo[nId].nRandomPos = vRandom.size(); | |
105 | vRandom.push_back(nId); | |
106 | if (pnId) | |
107 | *pnId = nId; | |
108 | return &mapInfo[nId]; | |
109 | } | |
110 | ||
f621326c | 111 | void CAddrMan::SwapRandom(unsigned int nRndPos1, unsigned int nRndPos2) |
5fee401f PW |
112 | { |
113 | if (nRndPos1 == nRndPos2) | |
114 | return; | |
115 | ||
29a86a17 PW |
116 | assert(nRndPos1 < vRandom.size() && nRndPos2 < vRandom.size()); |
117 | ||
5fee401f PW |
118 | int nId1 = vRandom[nRndPos1]; |
119 | int nId2 = vRandom[nRndPos2]; | |
120 | ||
29a86a17 PW |
121 | assert(mapInfo.count(nId1) == 1); |
122 | assert(mapInfo.count(nId2) == 1); | |
123 | ||
5fee401f PW |
124 | mapInfo[nId1].nRandomPos = nRndPos2; |
125 | mapInfo[nId2].nRandomPos = nRndPos1; | |
126 | ||
127 | vRandom[nRndPos1] = nId2; | |
128 | vRandom[nRndPos2] = nId1; | |
129 | } | |
130 | ||
131 | int CAddrMan::SelectTried(int nKBucket) | |
132 | { | |
20e01b1a | 133 | std::vector<int>& vTried = vvTried[nKBucket]; |
5fee401f PW |
134 | |
135 | // random shuffle the first few elements (using the entire list) | |
136 | // find the least recently tried among them | |
51ed9ec9 | 137 | int64_t nOldest = -1; |
56f1e912 | 138 | int nOldestPos = -1; |
20e01b1a | 139 | for (unsigned int i = 0; i < ADDRMAN_TRIED_ENTRIES_INSPECT_ON_EVICT && i < vTried.size(); i++) { |
5fee401f PW |
140 | int nPos = GetRandInt(vTried.size() - i) + i; |
141 | int nTemp = vTried[nPos]; | |
142 | vTried[nPos] = vTried[i]; | |
143 | vTried[i] = nTemp; | |
29a86a17 | 144 | assert(nOldest == -1 || mapInfo.count(nTemp) == 1); |
56f1e912 | 145 | if (nOldest == -1 || mapInfo[nTemp].nLastSuccess < mapInfo[nOldest].nLastSuccess) { |
20e01b1a PW |
146 | nOldest = nTemp; |
147 | nOldestPos = nPos; | |
56f1e912 | 148 | } |
5fee401f PW |
149 | } |
150 | ||
56f1e912 | 151 | return nOldestPos; |
5fee401f PW |
152 | } |
153 | ||
154 | int CAddrMan::ShrinkNew(int nUBucket) | |
155 | { | |
f621326c | 156 | assert(nUBucket >= 0 && (unsigned int)nUBucket < vvNew.size()); |
20e01b1a | 157 | std::set<int>& vNew = vvNew[nUBucket]; |
5fee401f PW |
158 | |
159 | // first look for deletable items | |
20e01b1a | 160 | for (std::set<int>::iterator it = vNew.begin(); it != vNew.end(); it++) { |
29a86a17 | 161 | assert(mapInfo.count(*it)); |
20e01b1a PW |
162 | CAddrInfo& info = mapInfo[*it]; |
163 | if (info.IsTerrible()) { | |
164 | if (--info.nRefCount == 0) { | |
165 | SwapRandom(info.nRandomPos, vRandom.size() - 1); | |
5fee401f PW |
166 | vRandom.pop_back(); |
167 | mapAddr.erase(info); | |
168 | mapInfo.erase(*it); | |
169 | nNew--; | |
170 | } | |
171 | vNew.erase(it); | |
172 | return 0; | |
173 | } | |
174 | } | |
175 | ||
176 | // otherwise, select four randomly, and pick the oldest of those to replace | |
177 | int n[4] = {GetRandInt(vNew.size()), GetRandInt(vNew.size()), GetRandInt(vNew.size()), GetRandInt(vNew.size())}; | |
178 | int nI = 0; | |
179 | int nOldest = -1; | |
20e01b1a PW |
180 | for (std::set<int>::iterator it = vNew.begin(); it != vNew.end(); it++) { |
181 | if (nI == n[0] || nI == n[1] || nI == n[2] || nI == n[3]) { | |
29a86a17 | 182 | assert(nOldest == -1 || mapInfo.count(*it) == 1); |
5fee401f PW |
183 | if (nOldest == -1 || mapInfo[*it].nTime < mapInfo[nOldest].nTime) |
184 | nOldest = *it; | |
185 | } | |
186 | nI++; | |
187 | } | |
29a86a17 | 188 | assert(mapInfo.count(nOldest) == 1); |
20e01b1a PW |
189 | CAddrInfo& info = mapInfo[nOldest]; |
190 | if (--info.nRefCount == 0) { | |
191 | SwapRandom(info.nRandomPos, vRandom.size() - 1); | |
5fee401f PW |
192 | vRandom.pop_back(); |
193 | mapAddr.erase(info); | |
194 | mapInfo.erase(nOldest); | |
195 | nNew--; | |
196 | } | |
197 | vNew.erase(nOldest); | |
198 | ||
199 | return 1; | |
200 | } | |
201 | ||
202 | void CAddrMan::MakeTried(CAddrInfo& info, int nId, int nOrigin) | |
203 | { | |
29a86a17 PW |
204 | assert(vvNew[nOrigin].count(nId) == 1); |
205 | ||
5fee401f | 206 | // remove the entry from all new buckets |
20e01b1a | 207 | for (std::vector<std::set<int> >::iterator it = vvNew.begin(); it != vvNew.end(); it++) { |
5fee401f PW |
208 | if ((*it).erase(nId)) |
209 | info.nRefCount--; | |
210 | } | |
211 | nNew--; | |
212 | ||
29a86a17 PW |
213 | assert(info.nRefCount == 0); |
214 | ||
5fee401f PW |
215 | // what tried bucket to move the entry to |
216 | int nKBucket = info.GetTriedBucket(nKey); | |
20e01b1a | 217 | std::vector<int>& vTried = vvTried[nKBucket]; |
5fee401f PW |
218 | |
219 | // first check whether there is place to just add it | |
20e01b1a | 220 | if (vTried.size() < ADDRMAN_TRIED_BUCKET_SIZE) { |
5fee401f PW |
221 | vTried.push_back(nId); |
222 | nTried++; | |
223 | info.fInTried = true; | |
224 | return; | |
225 | } | |
226 | ||
227 | // otherwise, find an item to evict | |
228 | int nPos = SelectTried(nKBucket); | |
229 | ||
230 | // find which new bucket it belongs to | |
29a86a17 | 231 | assert(mapInfo.count(vTried[nPos]) == 1); |
5fee401f | 232 | int nUBucket = mapInfo[vTried[nPos]].GetNewBucket(nKey); |
20e01b1a | 233 | std::set<int>& vNew = vvNew[nUBucket]; |
5fee401f PW |
234 | |
235 | // remove the to-be-replaced tried entry from the tried set | |
236 | CAddrInfo& infoOld = mapInfo[vTried[nPos]]; | |
237 | infoOld.fInTried = false; | |
238 | infoOld.nRefCount = 1; | |
239 | // do not update nTried, as we are going to move something else there immediately | |
240 | ||
ea0796bd | 241 | // check whether there is place in that one, |
20e01b1a | 242 | if (vNew.size() < ADDRMAN_NEW_BUCKET_SIZE) { |
5fee401f PW |
243 | // if so, move it back there |
244 | vNew.insert(vTried[nPos]); | |
245 | } else { | |
246 | // otherwise, move it to the new bucket nId came from (there is certainly place there) | |
247 | vvNew[nOrigin].insert(vTried[nPos]); | |
248 | } | |
249 | nNew++; | |
250 | ||
251 | vTried[nPos] = nId; | |
252 | // we just overwrote an entry in vTried; no need to update nTried | |
253 | info.fInTried = true; | |
254 | return; | |
255 | } | |
256 | ||
20e01b1a | 257 | void CAddrMan::Good_(const CService& addr, int64_t nTime) |
5fee401f | 258 | { |
5fee401f | 259 | int nId; |
20e01b1a | 260 | CAddrInfo* pinfo = Find(addr, &nId); |
5fee401f PW |
261 | |
262 | // if not found, bail out | |
263 | if (!pinfo) | |
264 | return; | |
265 | ||
20e01b1a | 266 | CAddrInfo& info = *pinfo; |
5fee401f PW |
267 | |
268 | // check whether we are talking about the exact same CService (including same port) | |
269 | if (info != addr) | |
270 | return; | |
271 | ||
272 | // update info | |
273 | info.nLastSuccess = nTime; | |
274 | info.nLastTry = nTime; | |
275 | info.nTime = nTime; | |
276 | info.nAttempts = 0; | |
277 | ||
278 | // if it is already in the tried set, don't do anything else | |
279 | if (info.fInTried) | |
280 | return; | |
281 | ||
282 | // find a bucket it is in now | |
283 | int nRnd = GetRandInt(vvNew.size()); | |
284 | int nUBucket = -1; | |
20e01b1a PW |
285 | for (unsigned int n = 0; n < vvNew.size(); n++) { |
286 | int nB = (n + nRnd) % vvNew.size(); | |
287 | std::set<int>& vNew = vvNew[nB]; | |
288 | if (vNew.count(nId)) { | |
5fee401f PW |
289 | nUBucket = nB; |
290 | break; | |
291 | } | |
292 | } | |
293 | ||
294 | // if no bucket is found, something bad happened; | |
295 | // TODO: maybe re-add the node, but for now, just bail out | |
20e01b1a PW |
296 | if (nUBucket == -1) |
297 | return; | |
5fee401f | 298 | |
7d9d134b | 299 | LogPrint("addrman", "Moving %s to tried\n", addr.ToString()); |
5fee401f PW |
300 | |
301 | // move nId to the tried tables | |
302 | MakeTried(info, nId, nUBucket); | |
303 | } | |
304 | ||
20e01b1a | 305 | bool CAddrMan::Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimePenalty) |
5fee401f PW |
306 | { |
307 | if (!addr.IsRoutable()) | |
308 | return false; | |
309 | ||
310 | bool fNew = false; | |
311 | int nId; | |
20e01b1a | 312 | CAddrInfo* pinfo = Find(addr, &nId); |
5fee401f | 313 | |
20e01b1a | 314 | if (pinfo) { |
5fee401f PW |
315 | // periodically update nTime |
316 | bool fCurrentlyOnline = (GetAdjustedTime() - addr.nTime < 24 * 60 * 60); | |
51ed9ec9 | 317 | int64_t nUpdateInterval = (fCurrentlyOnline ? 60 * 60 : 24 * 60 * 60); |
5fee401f | 318 | if (addr.nTime && (!pinfo->nTime || pinfo->nTime < addr.nTime - nUpdateInterval - nTimePenalty)) |
51ed9ec9 | 319 | pinfo->nTime = max((int64_t)0, addr.nTime - nTimePenalty); |
5fee401f PW |
320 | |
321 | // add services | |
322 | pinfo->nServices |= addr.nServices; | |
323 | ||
324 | // do not update if no new information is present | |
6642ffb7 | 325 | if (!addr.nTime || (pinfo->nTime && addr.nTime <= pinfo->nTime)) |
5fee401f PW |
326 | return false; |
327 | ||
328 | // do not update if the entry was already in the "tried" table | |
329 | if (pinfo->fInTried) | |
330 | return false; | |
331 | ||
332 | // do not update if the max reference count is reached | |
333 | if (pinfo->nRefCount == ADDRMAN_NEW_BUCKETS_PER_ADDRESS) | |
334 | return false; | |
335 | ||
336 | // stochastic test: previous nRefCount == N: 2^N times harder to increase it | |
337 | int nFactor = 1; | |
20e01b1a | 338 | for (int n = 0; n < pinfo->nRefCount; n++) |
5fee401f PW |
339 | nFactor *= 2; |
340 | if (nFactor > 1 && (GetRandInt(nFactor) != 0)) | |
341 | return false; | |
342 | } else { | |
343 | pinfo = Create(addr, source, &nId); | |
51ed9ec9 | 344 | pinfo->nTime = max((int64_t)0, (int64_t)pinfo->nTime - nTimePenalty); |
5fee401f PW |
345 | nNew++; |
346 | fNew = true; | |
347 | } | |
348 | ||
349 | int nUBucket = pinfo->GetNewBucket(nKey, source); | |
20e01b1a PW |
350 | std::set<int>& vNew = vvNew[nUBucket]; |
351 | if (!vNew.count(nId)) { | |
5fee401f PW |
352 | pinfo->nRefCount++; |
353 | if (vNew.size() == ADDRMAN_NEW_BUCKET_SIZE) | |
354 | ShrinkNew(nUBucket); | |
355 | vvNew[nUBucket].insert(nId); | |
356 | } | |
357 | return fNew; | |
358 | } | |
359 | ||
20e01b1a | 360 | void CAddrMan::Attempt_(const CService& addr, int64_t nTime) |
5fee401f | 361 | { |
20e01b1a | 362 | CAddrInfo* pinfo = Find(addr); |
5fee401f PW |
363 | |
364 | // if not found, bail out | |
365 | if (!pinfo) | |
366 | return; | |
367 | ||
20e01b1a | 368 | CAddrInfo& info = *pinfo; |
5fee401f PW |
369 | |
370 | // check whether we are talking about the exact same CService (including same port) | |
371 | if (info != addr) | |
372 | return; | |
373 | ||
374 | // update info | |
375 | info.nLastTry = nTime; | |
376 | info.nAttempts++; | |
377 | } | |
378 | ||
379 | CAddress CAddrMan::Select_(int nUnkBias) | |
380 | { | |
381 | if (size() == 0) | |
382 | return CAddress(); | |
383 | ||
384 | double nCorTried = sqrt(nTried) * (100.0 - nUnkBias); | |
385 | double nCorNew = sqrt(nNew) * nUnkBias; | |
20e01b1a | 386 | if ((nCorTried + nCorNew) * GetRandInt(1 << 30) / (1 << 30) < nCorTried) { |
5fee401f PW |
387 | // use a tried node |
388 | double fChanceFactor = 1.0; | |
20e01b1a | 389 | while (1) { |
5fee401f | 390 | int nKBucket = GetRandInt(vvTried.size()); |
20e01b1a PW |
391 | std::vector<int>& vTried = vvTried[nKBucket]; |
392 | if (vTried.size() == 0) | |
393 | continue; | |
5fee401f | 394 | int nPos = GetRandInt(vTried.size()); |
29a86a17 | 395 | assert(mapInfo.count(vTried[nPos]) == 1); |
20e01b1a PW |
396 | CAddrInfo& info = mapInfo[vTried[nPos]]; |
397 | if (GetRandInt(1 << 30) < fChanceFactor * info.GetChance() * (1 << 30)) | |
5fee401f PW |
398 | return info; |
399 | fChanceFactor *= 1.2; | |
400 | } | |
401 | } else { | |
30c8a408 | 402 | // use a new node |
5fee401f | 403 | double fChanceFactor = 1.0; |
20e01b1a | 404 | while (1) { |
5fee401f | 405 | int nUBucket = GetRandInt(vvNew.size()); |
20e01b1a PW |
406 | std::set<int>& vNew = vvNew[nUBucket]; |
407 | if (vNew.size() == 0) | |
408 | continue; | |
5fee401f PW |
409 | int nPos = GetRandInt(vNew.size()); |
410 | std::set<int>::iterator it = vNew.begin(); | |
411 | while (nPos--) | |
412 | it++; | |
29a86a17 | 413 | assert(mapInfo.count(*it) == 1); |
20e01b1a PW |
414 | CAddrInfo& info = mapInfo[*it]; |
415 | if (GetRandInt(1 << 30) < fChanceFactor * info.GetChance() * (1 << 30)) | |
5fee401f PW |
416 | return info; |
417 | fChanceFactor *= 1.2; | |
418 | } | |
419 | } | |
420 | } | |
421 | ||
422 | #ifdef DEBUG_ADDRMAN | |
423 | int CAddrMan::Check_() | |
424 | { | |
425 | std::set<int> setTried; | |
426 | std::map<int, int> mapNew; | |
427 | ||
20e01b1a PW |
428 | if (vRandom.size() != nTried + nNew) |
429 | return -7; | |
5fee401f | 430 | |
20e01b1a | 431 | for (std::map<int, CAddrInfo>::iterator it = mapInfo.begin(); it != mapInfo.end(); it++) { |
5fee401f | 432 | int n = (*it).first; |
20e01b1a PW |
433 | CAddrInfo& info = (*it).second; |
434 | if (info.fInTried) { | |
435 | if (!info.nLastSuccess) | |
436 | return -1; | |
437 | if (info.nRefCount) | |
438 | return -2; | |
5fee401f PW |
439 | setTried.insert(n); |
440 | } else { | |
20e01b1a PW |
441 | if (info.nRefCount < 0 || info.nRefCount > ADDRMAN_NEW_BUCKETS_PER_ADDRESS) |
442 | return -3; | |
443 | if (!info.nRefCount) | |
444 | return -4; | |
5fee401f PW |
445 | mapNew[n] = info.nRefCount; |
446 | } | |
20e01b1a PW |
447 | if (mapAddr[info] != n) |
448 | return -5; | |
449 | if (info.nRandomPos < 0 || info.nRandomPos >= vRandom.size() || vRandom[info.nRandomPos] != n) | |
450 | return -14; | |
451 | if (info.nLastTry < 0) | |
452 | return -6; | |
453 | if (info.nLastSuccess < 0) | |
454 | return -8; | |
5fee401f PW |
455 | } |
456 | ||
20e01b1a PW |
457 | if (setTried.size() != nTried) |
458 | return -9; | |
459 | if (mapNew.size() != nNew) | |
460 | return -10; | |
5fee401f | 461 | |
20e01b1a PW |
462 | for (int n = 0; n < vvTried.size(); n++) { |
463 | std::vector<int>& vTried = vvTried[n]; | |
464 | for (std::vector<int>::iterator it = vTried.begin(); it != vTried.end(); it++) { | |
465 | if (!setTried.count(*it)) | |
466 | return -11; | |
5fee401f PW |
467 | setTried.erase(*it); |
468 | } | |
469 | } | |
470 | ||
20e01b1a PW |
471 | for (int n = 0; n < vvNew.size(); n++) { |
472 | std::set<int>& vNew = vvNew[n]; | |
473 | for (std::set<int>::iterator it = vNew.begin(); it != vNew.end(); it++) { | |
474 | if (!mapNew.count(*it)) | |
475 | return -12; | |
5fee401f PW |
476 | if (--mapNew[*it] == 0) |
477 | mapNew.erase(*it); | |
478 | } | |
479 | } | |
480 | ||
20e01b1a PW |
481 | if (setTried.size()) |
482 | return -13; | |
483 | if (mapNew.size()) | |
484 | return -15; | |
5fee401f PW |
485 | |
486 | return 0; | |
487 | } | |
488 | #endif | |
489 | ||
20e01b1a | 490 | void CAddrMan::GetAddr_(std::vector<CAddress>& vAddr) |
5fee401f | 491 | { |
3a56de7f | 492 | unsigned int nNodes = ADDRMAN_GETADDR_MAX_PCT * vRandom.size() / 100; |
5fee401f PW |
493 | if (nNodes > ADDRMAN_GETADDR_MAX) |
494 | nNodes = ADDRMAN_GETADDR_MAX; | |
495 | ||
3a56de7f | 496 | // gather a list of random nodes, skipping those of low quality |
20e01b1a | 497 | for (unsigned int n = 0; n < vRandom.size(); n++) { |
3a56de7f JG |
498 | if (vAddr.size() >= nNodes) |
499 | break; | |
500 | ||
5fee401f PW |
501 | int nRndPos = GetRandInt(vRandom.size() - n) + n; |
502 | SwapRandom(n, nRndPos); | |
29a86a17 | 503 | assert(mapInfo.count(vRandom[n]) == 1); |
3a56de7f JG |
504 | |
505 | const CAddrInfo& ai = mapInfo[vRandom[n]]; | |
506 | if (!ai.IsTerrible()) | |
507 | vAddr.push_back(ai); | |
5fee401f PW |
508 | } |
509 | } | |
510 | ||
20e01b1a | 511 | void CAddrMan::Connected_(const CService& addr, int64_t nTime) |
5fee401f | 512 | { |
20e01b1a | 513 | CAddrInfo* pinfo = Find(addr); |
5fee401f PW |
514 | |
515 | // if not found, bail out | |
516 | if (!pinfo) | |
517 | return; | |
518 | ||
20e01b1a | 519 | CAddrInfo& info = *pinfo; |
5fee401f PW |
520 | |
521 | // check whether we are talking about the exact same CService (including same port) | |
522 | if (info != addr) | |
523 | return; | |
524 | ||
525 | // update info | |
51ed9ec9 | 526 | int64_t nUpdateInterval = 20 * 60; |
5fee401f PW |
527 | if (nTime - info.nTime > nUpdateInterval) |
528 | info.nTime = nTime; | |
529 | } |