]>
Commit | Line | Data |
---|---|---|
5fee401f | 1 | // Copyright (c) 2012 Pieter Wuille |
24f5c940 | 2 | // Distributed under the MIT software license, see the accompanying |
3a25a2b9 | 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. |
51ed9ec9 | 4 | |
84738627 PJ |
5 | #ifndef BITCOIN_ADDRMAN_H |
6 | #define BITCOIN_ADDRMAN_H | |
5fee401f PW |
7 | |
8 | #include "netbase.h" | |
9 | #include "protocol.h" | |
6354935c | 10 | #include "random.h" |
7f3ccb59 | 11 | #include "sync.h" |
14f888ca | 12 | #include "timedata.h" |
51ed9ec9 | 13 | #include "util.h" |
5fee401f PW |
14 | |
15 | #include <map> | |
51ed9ec9 BD |
16 | #include <set> |
17 | #include <stdint.h> | |
5fee401f PW |
18 | #include <vector> |
19 | ||
7e6d23b1 CD |
20 | /** |
21 | * Extended statistics about a CAddress | |
24f5c940 | 22 | */ |
5fee401f PW |
23 | class CAddrInfo : public CAddress |
24 | { | |
8375e1a3 E |
25 | |
26 | ||
1d5b47a9 PW |
27 | public: |
28 | //! last try whatsoever by us (memory only) | |
29 | int64_t nLastTry; | |
30 | ||
5fee401f | 31 | private: |
24f5c940 | 32 | //! where knowledge about this address first came from |
5fee401f PW |
33 | CNetAddr source; |
34 | ||
24f5c940 | 35 | //! last successful connection by us |
51ed9ec9 | 36 | int64_t nLastSuccess; |
5fee401f | 37 | |
24f5c940 | 38 | //! connection attempts since last successful attempt |
5fee401f PW |
39 | int nAttempts; |
40 | ||
24f5c940 | 41 | //! reference count in new sets (memory only) |
5fee401f PW |
42 | int nRefCount; |
43 | ||
24f5c940 | 44 | //! in tried set? (memory only) |
5fee401f PW |
45 | bool fInTried; |
46 | ||
24f5c940 | 47 | //! position in vRandom |
5fee401f PW |
48 | int nRandomPos; |
49 | ||
50 | friend class CAddrMan; | |
51 | ||
52 | public: | |
53 | ||
3f6540ad | 54 | ADD_SERIALIZE_METHODS; |
3d796f89 | 55 | |
84881f8c | 56 | template <typename Stream, typename Operation> |
31e9a838 PW |
57 | inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { |
58 | READWRITE(*(CAddress*)this); | |
5fee401f PW |
59 | READWRITE(source); |
60 | READWRITE(nLastSuccess); | |
61 | READWRITE(nAttempts); | |
3d796f89 | 62 | } |
5fee401f PW |
63 | |
64 | void Init() | |
65 | { | |
66 | nLastSuccess = 0; | |
67 | nLastTry = 0; | |
68 | nAttempts = 0; | |
69 | nRefCount = 0; | |
70 | fInTried = false; | |
71 | nRandomPos = -1; | |
72 | } | |
73 | ||
bd1aabe9 | 74 | CAddrInfo(const CAddress &addrIn, const CNetAddr &addrSource) : CAddress(addrIn), source(addrSource) |
5fee401f PW |
75 | { |
76 | Init(); | |
77 | } | |
78 | ||
79 | CAddrInfo() : CAddress(), source() | |
80 | { | |
81 | Init(); | |
82 | } | |
83 | ||
24f5c940 | 84 | //! Calculate in which "tried" bucket this entry belongs |
b23add55 | 85 | int GetTriedBucket(const uint256 &nKey) const; |
5fee401f | 86 | |
24f5c940 | 87 | //! Calculate in which "new" bucket this entry belongs, given a certain source |
b23add55 | 88 | int GetNewBucket(const uint256 &nKey, const CNetAddr& src) const; |
5fee401f | 89 | |
24f5c940 | 90 | //! Calculate in which "new" bucket this entry belongs, using its default source |
b23add55 | 91 | int GetNewBucket(const uint256 &nKey) const |
5fee401f PW |
92 | { |
93 | return GetNewBucket(nKey, source); | |
94 | } | |
95 | ||
e6b343d8 PW |
96 | //! Calculate in which position of a bucket to store this entry. |
97 | int GetBucketPosition(const uint256 &nKey, bool fNew, int nBucket) const; | |
98 | ||
24f5c940 | 99 | //! Determine whether the statistics about this entry are bad enough so that it can just be deleted |
51ed9ec9 | 100 | bool IsTerrible(int64_t nNow = GetAdjustedTime()) const; |
5fee401f | 101 | |
24f5c940 | 102 | //! Calculate the relative chance this entry should be given when selecting nodes to connect to |
51ed9ec9 | 103 | double GetChance(int64_t nNow = GetAdjustedTime()) const; |
5fee401f PW |
104 | |
105 | }; | |
106 | ||
24f5c940 MF |
107 | /** Stochastic address manager |
108 | * | |
109 | * Design goals: | |
b05a89b2 | 110 | * * Keep the address tables in-memory, and asynchronously dump the entire table to peers.dat. |
24f5c940 MF |
111 | * * Make sure no (localized) attacker can fill the entire table with his nodes/addresses. |
112 | * | |
113 | * To that end: | |
114 | * * Addresses are organized into buckets. | |
f13dac97 B |
115 | * * Addresses that have not yet been tried go into 1024 "new" buckets. |
116 | * * Based on the address range (/16 for IPv4) of the source of information, 64 buckets are selected at random. | |
7e6d23b1 | 117 | * * The actual bucket is chosen from one of these, based on the range in which the address itself is located. |
f13dac97 | 118 | * * One single address can occur in up to 8 different buckets to increase selection chances for addresses that |
24f5c940 MF |
119 | * are seen frequently. The chance for increasing this multiplicity decreases exponentially. |
120 | * * When adding a new address to a full bucket, a randomly chosen entry (with a bias favoring less recently seen | |
121 | * ones) is removed from it first. | |
1d21ba2f PW |
122 | * * Addresses of nodes that are known to be accessible go into 256 "tried" buckets. |
123 | * * Each address range selects at random 8 of these buckets. | |
24f5c940 MF |
124 | * * The actual bucket is chosen from one of these, based on the full address. |
125 | * * When adding a new good address to a full bucket, a randomly chosen entry (with a bias favoring less recently | |
126 | * tried ones) is evicted from it, back to the "new" buckets. | |
127 | * * Bucket selection is based on cryptographic hashing, using a randomly-generated 256-bit key, which should not | |
128 | * be observable by adversaries. | |
129 | * * Several indexes are kept for high performance. Defining DEBUG_ADDRMAN will introduce frequent (and expensive) | |
130 | * consistency checks for the entire data structure. | |
131 | */ | |
132 | ||
133 | //! total number of buckets for tried addresses | |
1d21ba2f | 134 | #define ADDRMAN_TRIED_BUCKET_COUNT 256 |
5fee401f | 135 | |
24f5c940 | 136 | //! total number of buckets for new addresses |
1d21ba2f | 137 | #define ADDRMAN_NEW_BUCKET_COUNT 1024 |
5fee401f | 138 | |
e6b343d8 PW |
139 | //! maximum allowed number of entries in buckets for new and tried addresses |
140 | #define ADDRMAN_BUCKET_SIZE 64 | |
5fee401f | 141 | |
24f5c940 | 142 | //! over how many buckets entries with tried addresses from a single group (/16 for IPv4) are spread |
1d21ba2f | 143 | #define ADDRMAN_TRIED_BUCKETS_PER_GROUP 8 |
5fee401f | 144 | |
24f5c940 | 145 | //! over how many buckets entries with new addresses originating from a single group are spread |
1d21ba2f | 146 | #define ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP 64 |
5fee401f | 147 | |
24f5c940 | 148 | //! in how many buckets for entries with new addresses a single address may occur |
1d21ba2f | 149 | #define ADDRMAN_NEW_BUCKETS_PER_ADDRESS 8 |
5fee401f | 150 | |
24f5c940 | 151 | //! how old addresses can maximally be |
5fee401f PW |
152 | #define ADDRMAN_HORIZON_DAYS 30 |
153 | ||
24f5c940 | 154 | //! after how many failed attempts we give up on a new node |
5fee401f PW |
155 | #define ADDRMAN_RETRIES 3 |
156 | ||
24f5c940 | 157 | //! how many successive failures are allowed ... |
5fee401f PW |
158 | #define ADDRMAN_MAX_FAILURES 10 |
159 | ||
24f5c940 | 160 | //! ... in at least this many days |
5fee401f PW |
161 | #define ADDRMAN_MIN_FAIL_DAYS 7 |
162 | ||
24f5c940 | 163 | //! the maximum percentage of nodes to return in a getaddr call |
5fee401f PW |
164 | #define ADDRMAN_GETADDR_MAX_PCT 23 |
165 | ||
24f5c940 | 166 | //! the maximum number of nodes to return in a getaddr call |
5fee401f PW |
167 | #define ADDRMAN_GETADDR_MAX 2500 |
168 | ||
24f5c940 MF |
169 | /** |
170 | * Stochastical (IP) address manager | |
171 | */ | |
5fee401f PW |
172 | class CAddrMan |
173 | { | |
174 | private: | |
24f5c940 | 175 | //! critical section to protect the inner data structures |
5fee401f PW |
176 | mutable CCriticalSection cs; |
177 | ||
24f5c940 | 178 | //! last used nId |
5fee401f PW |
179 | int nIdCount; |
180 | ||
24f5c940 | 181 | //! table with information about all nIds |
5fee401f PW |
182 | std::map<int, CAddrInfo> mapInfo; |
183 | ||
24f5c940 | 184 | //! find an nId based on its network address |
5fee401f PW |
185 | std::map<CNetAddr, int> mapAddr; |
186 | ||
24f5c940 | 187 | //! randomly-ordered vector of all nIds |
5fee401f PW |
188 | std::vector<int> vRandom; |
189 | ||
190 | // number of "tried" entries | |
191 | int nTried; | |
192 | ||
24f5c940 | 193 | //! list of "tried" buckets |
e6b343d8 | 194 | int vvTried[ADDRMAN_TRIED_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE]; |
5fee401f | 195 | |
24f5c940 | 196 | //! number of (unique) "new" entries |
5fee401f PW |
197 | int nNew; |
198 | ||
24f5c940 | 199 | //! list of "new" buckets |
e6b343d8 | 200 | int vvNew[ADDRMAN_NEW_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE]; |
5fee401f PW |
201 | |
202 | protected: | |
1bf2cb1a EH |
203 | //! secret key to randomize bucket select with |
204 | uint256 nKey; | |
5fee401f | 205 | |
24f5c940 | 206 | //! Find an entry. |
5fee401f PW |
207 | CAddrInfo* Find(const CNetAddr& addr, int *pnId = NULL); |
208 | ||
24f5c940 MF |
209 | //! find an entry, creating it if necessary. |
210 | //! nTime and nServices of the found node are updated, if necessary. | |
5fee401f PW |
211 | CAddrInfo* Create(const CAddress &addr, const CNetAddr &addrSource, int *pnId = NULL); |
212 | ||
24f5c940 | 213 | //! Swap two elements in vRandom. |
f621326c | 214 | void SwapRandom(unsigned int nRandomPos1, unsigned int nRandomPos2); |
5fee401f | 215 | |
e6b343d8 PW |
216 | //! Move an entry from the "new" table(s) to the "tried" table |
217 | void MakeTried(CAddrInfo& info, int nId); | |
5fee401f | 218 | |
e6b343d8 PW |
219 | //! Delete an entry. It must not be in tried, and have refcount 0. |
220 | void Delete(int nId); | |
ea0796bd | 221 | |
e6b343d8 PW |
222 | //! Clear a position in a "new" table. This is the only place where entries are actually deleted. |
223 | void ClearNew(int nUBucket, int nUBucketPos); | |
5fee401f | 224 | |
24f5c940 | 225 | //! Mark an entry "good", possibly moving it from "new" to "tried". |
51ed9ec9 | 226 | void Good_(const CService &addr, int64_t nTime); |
5fee401f | 227 | |
24f5c940 | 228 | //! Add an entry to the "new" table. |
51ed9ec9 | 229 | bool Add_(const CAddress &addr, const CNetAddr& source, int64_t nTimePenalty); |
5fee401f | 230 | |
24f5c940 | 231 | //! Mark an entry as attempted to connect. |
51ed9ec9 | 232 | void Attempt_(const CService &addr, int64_t nTime); |
5fee401f | 233 | |
8375e1a3 E |
234 | //! Select an address to connect to, if newOnly is set to true, only the new table is selected from. |
235 | CAddrInfo Select_(bool newOnly); | |
5fee401f | 236 | |
1bf2cb1a EH |
237 | //! Wraps GetRandInt to allow tests to override RandomInt and make it determinismistic. |
238 | virtual int RandomInt(int nMax); | |
239 | ||
5fee401f | 240 | #ifdef DEBUG_ADDRMAN |
24f5c940 | 241 | //! Perform consistency check. Returns an error code or zero. |
5fee401f PW |
242 | int Check_(); |
243 | #endif | |
244 | ||
24f5c940 | 245 | //! Select several addresses at once. |
5fee401f PW |
246 | void GetAddr_(std::vector<CAddress> &vAddr); |
247 | ||
24f5c940 | 248 | //! Mark an entry as currently-connected-to. |
51ed9ec9 | 249 | void Connected_(const CService &addr, int64_t nTime); |
5fee401f PW |
250 | |
251 | public: | |
24f5c940 MF |
252 | /** |
253 | * serialized format: | |
e6b343d8 PW |
254 | * * version byte (currently 1) |
255 | * * 0x20 + nKey (serialized as if it were a vector, for backward compatibility) | |
24f5c940 MF |
256 | * * nNew |
257 | * * nTried | |
e6b343d8 | 258 | * * number of "new" buckets XOR 2**30 |
24f5c940 MF |
259 | * * all nNew addrinfos in vvNew |
260 | * * all nTried addrinfos in vvTried | |
261 | * * for each bucket: | |
262 | * * number of elements | |
263 | * * for each element: index | |
264 | * | |
e6b343d8 PW |
265 | * 2**30 is xorred with the number of buckets to make addrman deserializer v0 detect it |
266 | * as incompatible. This is necessary because it did not check the version number on | |
267 | * deserialization. | |
268 | * | |
24f5c940 MF |
269 | * Notice that vvTried, mapAddr and vVector are never encoded explicitly; |
270 | * they are instead reconstructed from the other information. | |
271 | * | |
45bfa137 | 272 | * vvNew is serialized, but only used if ADDRMAN_UNKNOWN_BUCKET_COUNT didn't change, |
24f5c940 MF |
273 | * otherwise it is reconstructed as well. |
274 | * | |
275 | * This format is more complex, but significantly smaller (at most 1.5 MiB), and supports | |
276 | * changes to the ADDRMAN_ parameters without breaking the on-disk structure. | |
277 | * | |
278 | * We don't use ADD_SERIALIZE_METHODS since the serialization and deserialization code has | |
279 | * very little in common. | |
24f5c940 | 280 | */ |
b069750d PW |
281 | template<typename Stream> |
282 | void Serialize(Stream &s, int nType, int nVersionDummy) const | |
283 | { | |
284 | LOCK(cs); | |
285 | ||
e6b343d8 | 286 | unsigned char nVersion = 1; |
b069750d | 287 | s << nVersion; |
b23add55 | 288 | s << ((unsigned char)32); |
b069750d PW |
289 | s << nKey; |
290 | s << nNew; | |
291 | s << nTried; | |
292 | ||
e6b343d8 | 293 | int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT ^ (1 << 30); |
b069750d PW |
294 | s << nUBuckets; |
295 | std::map<int, int> mapUnkIds; | |
296 | int nIds = 0; | |
297 | for (std::map<int, CAddrInfo>::const_iterator it = mapInfo.begin(); it != mapInfo.end(); it++) { | |
b069750d PW |
298 | mapUnkIds[(*it).first] = nIds; |
299 | const CAddrInfo &info = (*it).second; | |
300 | if (info.nRefCount) { | |
e6b343d8 | 301 | assert(nIds != nNew); // this means nNew was wrong, oh ow |
b069750d PW |
302 | s << info; |
303 | nIds++; | |
304 | } | |
305 | } | |
306 | nIds = 0; | |
307 | for (std::map<int, CAddrInfo>::const_iterator it = mapInfo.begin(); it != mapInfo.end(); it++) { | |
b069750d PW |
308 | const CAddrInfo &info = (*it).second; |
309 | if (info.fInTried) { | |
e6b343d8 | 310 | assert(nIds != nTried); // this means nTried was wrong, oh ow |
b069750d PW |
311 | s << info; |
312 | nIds++; | |
313 | } | |
314 | } | |
e6b343d8 PW |
315 | for (int bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) { |
316 | int nSize = 0; | |
317 | for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) { | |
318 | if (vvNew[bucket][i] != -1) | |
319 | nSize++; | |
320 | } | |
b069750d | 321 | s << nSize; |
e6b343d8 PW |
322 | for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) { |
323 | if (vvNew[bucket][i] != -1) { | |
324 | int nIndex = mapUnkIds[vvNew[bucket][i]]; | |
325 | s << nIndex; | |
326 | } | |
b069750d PW |
327 | } |
328 | } | |
329 | } | |
5fee401f | 330 | |
b069750d PW |
331 | template<typename Stream> |
332 | void Unserialize(Stream& s, int nType, int nVersionDummy) | |
333 | { | |
334 | LOCK(cs); | |
335 | ||
e6b343d8 PW |
336 | Clear(); |
337 | ||
b069750d PW |
338 | unsigned char nVersion; |
339 | s >> nVersion; | |
b23add55 PW |
340 | unsigned char nKeySize; |
341 | s >> nKeySize; | |
e6b343d8 | 342 | if (nKeySize != 32) throw std::ios_base::failure("Incorrect keysize in addrman deserialization"); |
b069750d PW |
343 | s >> nKey; |
344 | s >> nNew; | |
345 | s >> nTried; | |
b069750d PW |
346 | int nUBuckets = 0; |
347 | s >> nUBuckets; | |
e6b343d8 PW |
348 | if (nVersion != 0) { |
349 | nUBuckets ^= (1 << 30); | |
350 | } | |
351 | ||
7bfb552f PS |
352 | if (nNew > ADDRMAN_NEW_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE) { |
353 | throw std::ios_base::failure("Corrupt CAddrMan serialization, nNew exceeds limit."); | |
354 | } | |
355 | ||
356 | if (nTried > ADDRMAN_TRIED_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE) { | |
357 | throw std::ios_base::failure("Corrupt CAddrMan serialization, nTried exceeds limit."); | |
358 | } | |
359 | ||
e6b343d8 | 360 | // Deserialize entries from the new table. |
b069750d PW |
361 | for (int n = 0; n < nNew; n++) { |
362 | CAddrInfo &info = mapInfo[n]; | |
363 | s >> info; | |
364 | mapAddr[info] = n; | |
365 | info.nRandomPos = vRandom.size(); | |
366 | vRandom.push_back(n); | |
e6b343d8 PW |
367 | if (nVersion != 1 || nUBuckets != ADDRMAN_NEW_BUCKET_COUNT) { |
368 | // In case the new table data cannot be used (nVersion unknown, or bucket count wrong), | |
369 | // immediately try to give them a reference based on their primary source address. | |
370 | int nUBucket = info.GetNewBucket(nKey); | |
371 | int nUBucketPos = info.GetBucketPosition(nKey, true, nUBucket); | |
372 | if (vvNew[nUBucket][nUBucketPos] == -1) { | |
373 | vvNew[nUBucket][nUBucketPos] = n; | |
374 | info.nRefCount++; | |
375 | } | |
b069750d PW |
376 | } |
377 | } | |
378 | nIdCount = nNew; | |
e6b343d8 PW |
379 | |
380 | // Deserialize entries from the tried table. | |
b069750d PW |
381 | int nLost = 0; |
382 | for (int n = 0; n < nTried; n++) { | |
383 | CAddrInfo info; | |
384 | s >> info; | |
e6b343d8 PW |
385 | int nKBucket = info.GetTriedBucket(nKey); |
386 | int nKBucketPos = info.GetBucketPosition(nKey, false, nKBucket); | |
387 | if (vvTried[nKBucket][nKBucketPos] == -1) { | |
b069750d PW |
388 | info.nRandomPos = vRandom.size(); |
389 | info.fInTried = true; | |
390 | vRandom.push_back(nIdCount); | |
391 | mapInfo[nIdCount] = info; | |
392 | mapAddr[info] = nIdCount; | |
e6b343d8 | 393 | vvTried[nKBucket][nKBucketPos] = nIdCount; |
b069750d | 394 | nIdCount++; |
5fee401f | 395 | } else { |
b069750d PW |
396 | nLost++; |
397 | } | |
398 | } | |
399 | nTried -= nLost; | |
e6b343d8 PW |
400 | |
401 | // Deserialize positions in the new table (if possible). | |
402 | for (int bucket = 0; bucket < nUBuckets; bucket++) { | |
b069750d PW |
403 | int nSize = 0; |
404 | s >> nSize; | |
405 | for (int n = 0; n < nSize; n++) { | |
406 | int nIndex = 0; | |
407 | s >> nIndex; | |
e6b343d8 PW |
408 | if (nIndex >= 0 && nIndex < nNew) { |
409 | CAddrInfo &info = mapInfo[nIndex]; | |
410 | int nUBucketPos = info.GetBucketPosition(nKey, true, bucket); | |
411 | if (nVersion == 1 && nUBuckets == ADDRMAN_NEW_BUCKET_COUNT && vvNew[bucket][nUBucketPos] == -1 && info.nRefCount < ADDRMAN_NEW_BUCKETS_PER_ADDRESS) { | |
412 | info.nRefCount++; | |
413 | vvNew[bucket][nUBucketPos] = nIndex; | |
414 | } | |
5fee401f PW |
415 | } |
416 | } | |
417 | } | |
e6b343d8 PW |
418 | |
419 | // Prune new entries with refcount 0 (as a result of collisions). | |
420 | int nLostUnk = 0; | |
421 | for (std::map<int, CAddrInfo>::const_iterator it = mapInfo.begin(); it != mapInfo.end(); ) { | |
422 | if (it->second.fInTried == false && it->second.nRefCount == 0) { | |
423 | std::map<int, CAddrInfo>::const_iterator itCopy = it++; | |
424 | Delete(itCopy->first); | |
425 | nLostUnk++; | |
426 | } else { | |
427 | it++; | |
428 | } | |
429 | } | |
430 | if (nLost + nLostUnk > 0) { | |
431 | LogPrint("addrman", "addrman lost %i new and %i tried addresses due to collisions\n", nLostUnk, nLost); | |
432 | } | |
433 | ||
434 | Check(); | |
b069750d PW |
435 | } |
436 | ||
437 | unsigned int GetSerializeSize(int nType, int nVersion) const | |
438 | { | |
439 | return (CSizeComputer(nType, nVersion) << *this).size(); | |
440 | } | |
5fee401f | 441 | |
e6b343d8 | 442 | void Clear() |
5fee401f | 443 | { |
e6b343d8 PW |
444 | std::vector<int>().swap(vRandom); |
445 | nKey = GetRandHash(); | |
446 | for (size_t bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) { | |
447 | for (size_t entry = 0; entry < ADDRMAN_BUCKET_SIZE; entry++) { | |
448 | vvNew[bucket][entry] = -1; | |
449 | } | |
450 | } | |
451 | for (size_t bucket = 0; bucket < ADDRMAN_TRIED_BUCKET_COUNT; bucket++) { | |
452 | for (size_t entry = 0; entry < ADDRMAN_BUCKET_SIZE; entry++) { | |
453 | vvTried[bucket][entry] = -1; | |
454 | } | |
455 | } | |
5fee401f | 456 | |
e6b343d8 PW |
457 | nIdCount = 0; |
458 | nTried = 0; | |
459 | nNew = 0; | |
460 | } | |
461 | ||
462 | CAddrMan() | |
463 | { | |
464 | Clear(); | |
5fee401f PW |
465 | } |
466 | ||
b23add55 PW |
467 | ~CAddrMan() |
468 | { | |
e6b343d8 | 469 | nKey.SetNull(); |
b23add55 PW |
470 | } |
471 | ||
24f5c940 | 472 | //! Return the number of (unique) addresses in all tables. |
da757918 | 473 | size_t size() const |
5fee401f PW |
474 | { |
475 | return vRandom.size(); | |
476 | } | |
477 | ||
24f5c940 | 478 | //! Consistency check |
5fee401f PW |
479 | void Check() |
480 | { | |
481 | #ifdef DEBUG_ADDRMAN | |
5fee401f | 482 | { |
f8dcd5ca | 483 | LOCK(cs); |
5fee401f PW |
484 | int err; |
485 | if ((err=Check_())) | |
881a85a2 | 486 | LogPrintf("ADDRMAN CONSISTENCY CHECK FAILED!!! err=%i\n", err); |
5fee401f PW |
487 | } |
488 | #endif | |
489 | } | |
490 | ||
24f5c940 | 491 | //! Add a single address. |
51ed9ec9 | 492 | bool Add(const CAddress &addr, const CNetAddr& source, int64_t nTimePenalty = 0) |
5fee401f PW |
493 | { |
494 | bool fRet = false; | |
5fee401f | 495 | { |
f8dcd5ca | 496 | LOCK(cs); |
5fee401f PW |
497 | Check(); |
498 | fRet |= Add_(addr, source, nTimePenalty); | |
499 | Check(); | |
500 | } | |
501 | if (fRet) | |
2c2cc5da | 502 | LogPrint("addrman", "Added %s from %s: %i tried, %i new\n", addr.ToStringIPPort(), source.ToString(), nTried, nNew); |
5fee401f PW |
503 | return fRet; |
504 | } | |
505 | ||
24f5c940 | 506 | //! Add multiple addresses. |
51ed9ec9 | 507 | bool Add(const std::vector<CAddress> &vAddr, const CNetAddr& source, int64_t nTimePenalty = 0) |
5fee401f PW |
508 | { |
509 | int nAdd = 0; | |
5fee401f | 510 | { |
f8dcd5ca | 511 | LOCK(cs); |
5fee401f PW |
512 | Check(); |
513 | for (std::vector<CAddress>::const_iterator it = vAddr.begin(); it != vAddr.end(); it++) | |
514 | nAdd += Add_(*it, source, nTimePenalty) ? 1 : 0; | |
515 | Check(); | |
516 | } | |
517 | if (nAdd) | |
79d06dc6 | 518 | LogPrint("addrman", "Added %i addresses from %s: %i tried, %i new\n", nAdd, source.ToString(), nTried, nNew); |
5fee401f PW |
519 | return nAdd > 0; |
520 | } | |
521 | ||
24f5c940 | 522 | //! Mark an entry as accessible. |
51ed9ec9 | 523 | void Good(const CService &addr, int64_t nTime = GetAdjustedTime()) |
5fee401f | 524 | { |
5fee401f | 525 | { |
f8dcd5ca | 526 | LOCK(cs); |
5fee401f PW |
527 | Check(); |
528 | Good_(addr, nTime); | |
529 | Check(); | |
530 | } | |
531 | } | |
532 | ||
24f5c940 | 533 | //! Mark an entry as connection attempted to. |
51ed9ec9 | 534 | void Attempt(const CService &addr, int64_t nTime = GetAdjustedTime()) |
5fee401f | 535 | { |
5fee401f | 536 | { |
f8dcd5ca | 537 | LOCK(cs); |
5fee401f PW |
538 | Check(); |
539 | Attempt_(addr, nTime); | |
540 | Check(); | |
541 | } | |
542 | } | |
543 | ||
24f5c940 MF |
544 | /** |
545 | * Choose an address to connect to. | |
24f5c940 | 546 | */ |
8375e1a3 | 547 | CAddrInfo Select(bool newOnly = false) |
5fee401f | 548 | { |
1d5b47a9 | 549 | CAddrInfo addrRet; |
5fee401f | 550 | { |
f8dcd5ca | 551 | LOCK(cs); |
5fee401f | 552 | Check(); |
8375e1a3 | 553 | addrRet = Select_(newOnly); |
5fee401f PW |
554 | Check(); |
555 | } | |
556 | return addrRet; | |
557 | } | |
558 | ||
24f5c940 | 559 | //! Return a bunch of addresses, selected at random. |
5fee401f PW |
560 | std::vector<CAddress> GetAddr() |
561 | { | |
562 | Check(); | |
563 | std::vector<CAddress> vAddr; | |
f8dcd5ca PW |
564 | { |
565 | LOCK(cs); | |
5fee401f | 566 | GetAddr_(vAddr); |
f8dcd5ca | 567 | } |
5fee401f PW |
568 | Check(); |
569 | return vAddr; | |
570 | } | |
571 | ||
24f5c940 | 572 | //! Mark an entry as currently-connected-to. |
51ed9ec9 | 573 | void Connected(const CService &addr, int64_t nTime = GetAdjustedTime()) |
5fee401f | 574 | { |
5fee401f | 575 | { |
f8dcd5ca | 576 | LOCK(cs); |
5fee401f PW |
577 | Check(); |
578 | Connected_(addr, nTime); | |
579 | Check(); | |
580 | } | |
581 | } | |
8375e1a3 | 582 | |
5fee401f PW |
583 | }; |
584 | ||
84738627 | 585 | #endif // BITCOIN_ADDRMAN_H |