1use std::collections::HashMap;
23use std::net::{IpAddr, SocketAddr};
24
25const MAX_NEW_ADDRESSES: usize = 1024;
29
30const MAX_TRIED_ADDRESSES: usize = 256;
32
33const MAX_ADDRESS_AGE: u64 = 30 * 24 * 60 * 60;
35
36const MAX_ADDR_RESPONSE: usize = 1000;
38
39const GETADDR_PERCENT: usize = 23;
41
42#[derive(Debug, Clone)]
46pub struct AddressInfo {
47 pub addr: SocketAddr,
49 pub services: u64,
51 pub last_seen: u64,
53 pub last_success: u64,
55 pub attempts: u32,
57 pub source: IpAddr,
59 pub is_tried: bool,
61}
62
63#[derive(Debug, Clone, PartialEq, Eq)]
65pub enum AddResult {
66 Added,
68 Updated,
70 Rejected,
72}
73
74pub struct AddressManager {
79 addresses: HashMap<SocketAddr, AddressInfo>,
81 new_count: usize,
83 tried_count: usize,
85 selection_counter: u64,
87}
88
89impl AddressManager {
90 pub fn new() -> Self {
92 AddressManager {
93 addresses: HashMap::new(),
94 new_count: 0,
95 tried_count: 0,
96 selection_counter: 0,
97 }
98 }
99
100 pub fn size(&self) -> usize {
102 self.addresses.len()
103 }
104
105 pub fn new_count(&self) -> usize {
107 self.new_count
108 }
109
110 pub fn tried_count(&self) -> usize {
112 self.tried_count
113 }
114
115 pub fn add_address(
122 &mut self,
123 addr: SocketAddr,
124 services: u64,
125 source: IpAddr,
126 now: u64,
127 ) -> AddResult {
128 if !Self::is_routable(&addr) {
130 return AddResult::Rejected;
131 }
132
133 if let Some(existing) = self.addresses.get_mut(&addr) {
135 if now > existing.last_seen {
137 existing.last_seen = now;
138 }
139 if services > existing.services {
141 existing.services = services;
142 }
143 return AddResult::Updated;
144 }
145
146 if now > MAX_ADDRESS_AGE && self.addresses.values().any(|a| now - a.last_seen < 600) {
148 }
152
153 if self.new_count >= MAX_NEW_ADDRESSES {
155 self.evict_oldest_new(now);
156 if self.new_count >= MAX_NEW_ADDRESSES {
157 return AddResult::Rejected;
158 }
159 }
160
161 let info = AddressInfo {
162 addr,
163 services,
164 last_seen: now,
165 last_success: 0,
166 attempts: 0,
167 source,
168 is_tried: false,
169 };
170
171 self.addresses.insert(addr, info);
172 self.new_count += 1;
173
174 AddResult::Added
175 }
176
177 pub fn mark_good(&mut self, addr: &SocketAddr, now: u64) {
179 if let Some(info) = self.addresses.get_mut(addr) {
180 info.last_success = now;
181 info.last_seen = now;
182 info.attempts = 0;
183
184 if !info.is_tried {
185 info.is_tried = true;
186 self.new_count = self.new_count.saturating_sub(1);
187 self.tried_count += 1;
188
189 if self.tried_count > MAX_TRIED_ADDRESSES {
191 self.evict_oldest_tried(now);
192 }
193 }
194 }
195 }
196
197 pub fn mark_attempt(&mut self, addr: &SocketAddr, now: u64) {
199 if let Some(info) = self.addresses.get_mut(addr) {
200 info.attempts += 1;
201 info.last_seen = now;
202 }
203 }
204
205 pub fn get_addr_response(&mut self, now: u64) -> Vec<(u64, SocketAddr)> {
211 let all: Vec<&AddressInfo> = self
212 .addresses
213 .values()
214 .filter(|a| {
215 now.saturating_sub(a.last_seen) < MAX_ADDRESS_AGE
217 })
218 .collect();
219
220 if all.is_empty() {
221 return Vec::new();
222 }
223
224 let target = (all.len() * GETADDR_PERCENT / 100)
226 .clamp(1, MAX_ADDR_RESPONSE);
227
228 self.selection_counter = self.selection_counter.wrapping_add(1);
230 let offset = (self.selection_counter as usize) % all.len();
231
232 let mut result = Vec::with_capacity(target);
233 for i in 0..target {
234 let idx = (offset + i) % all.len();
235 let info = all[idx];
236 result.push((info.last_seen, info.addr));
237 }
238
239 result
240 }
241
242 pub fn select_for_connection(&mut self, count: usize, now: u64) -> Vec<SocketAddr> {
247 let min_retry_delay = 600u64; let mut tried: Vec<&AddressInfo> = self
251 .addresses
252 .values()
253 .filter(|a| a.is_tried && now.saturating_sub(a.last_seen) < MAX_ADDRESS_AGE)
254 .filter(|a| a.last_success == 0 || now.saturating_sub(a.last_success) > min_retry_delay)
255 .collect();
256
257 let mut new: Vec<&AddressInfo> = self
258 .addresses
259 .values()
260 .filter(|a| !a.is_tried && now.saturating_sub(a.last_seen) < MAX_ADDRESS_AGE)
261 .filter(|a| a.attempts == 0 || now.saturating_sub(a.last_seen) > min_retry_delay)
262 .collect();
263
264 tried.sort_by(|a, b| {
266 a.attempts
267 .cmp(&b.attempts)
268 .then(b.last_seen.cmp(&a.last_seen))
269 });
270 new.sort_by(|a, b| {
271 a.attempts
272 .cmp(&b.attempts)
273 .then(b.last_seen.cmp(&a.last_seen))
274 });
275
276 let mut result = Vec::with_capacity(count);
277
278 for info in tried.iter().take(count) {
280 result.push(info.addr);
281 }
282
283 let remaining = count.saturating_sub(result.len());
285 for info in new.iter().take(remaining) {
286 result.push(info.addr);
287 }
288
289 result
290 }
291
292 pub fn remove_by_source(&mut self, source: &IpAddr) {
294 let to_remove: Vec<SocketAddr> = self
295 .addresses
296 .iter()
297 .filter(|(_, info)| info.source == *source)
298 .map(|(addr, _)| *addr)
299 .collect();
300
301 for addr in to_remove {
302 if let Some(info) = self.addresses.remove(&addr) {
303 if info.is_tried {
304 self.tried_count = self.tried_count.saturating_sub(1);
305 } else {
306 self.new_count = self.new_count.saturating_sub(1);
307 }
308 }
309 }
310 }
311
312 pub fn expire_old(&mut self, now: u64) {
314 let to_remove: Vec<SocketAddr> = self
315 .addresses
316 .iter()
317 .filter(|(_, info)| now.saturating_sub(info.last_seen) >= MAX_ADDRESS_AGE)
318 .map(|(addr, _)| *addr)
319 .collect();
320
321 for addr in to_remove {
322 if let Some(info) = self.addresses.remove(&addr) {
323 if info.is_tried {
324 self.tried_count = self.tried_count.saturating_sub(1);
325 } else {
326 self.new_count = self.new_count.saturating_sub(1);
327 }
328 }
329 }
330 }
331
332 fn is_routable(addr: &SocketAddr) -> bool {
334 let ip = addr.ip();
335 !ip.is_loopback() && !ip.is_unspecified() && addr.port() > 0
336 }
337
338 fn evict_oldest_new(&mut self, _now: u64) {
340 let oldest = self
341 .addresses
342 .iter()
343 .filter(|(_, info)| !info.is_tried)
344 .min_by_key(|(_, info)| info.last_seen)
345 .map(|(addr, _)| *addr);
346
347 if let Some(addr) = oldest {
348 self.addresses.remove(&addr);
349 self.new_count = self.new_count.saturating_sub(1);
350 }
351 }
352
353 fn evict_oldest_tried(&mut self, _now: u64) {
355 let oldest = self
356 .addresses
357 .iter()
358 .filter(|(_, info)| info.is_tried)
359 .min_by_key(|(_, info)| info.last_success)
360 .map(|(addr, _)| *addr);
361
362 if let Some(addr) = oldest {
363 if let Some(info) = self.addresses.get_mut(&addr) {
364 info.is_tried = false;
365 self.tried_count = self.tried_count.saturating_sub(1);
366 self.new_count += 1;
367 }
368 }
369 }
370}
371
372impl Default for AddressManager {
373 fn default() -> Self {
374 Self::new()
375 }
376}
377
378#[cfg(test)]
379mod tests {
380 use super::*;
381 use std::net::{Ipv4Addr, SocketAddrV4};
382
383 fn addr(a: u8, b: u8, c: u8, d: u8, port: u16) -> SocketAddr {
384 SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(a, b, c, d), port))
385 }
386
387 fn source() -> IpAddr {
388 IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1))
389 }
390
391 #[test]
392 fn test_add_and_size() {
393 let mut mgr = AddressManager::new();
394 assert_eq!(mgr.size(), 0);
395
396 let result = mgr.add_address(addr(1, 2, 3, 4, 8333), 1, source(), 1000);
397 assert_eq!(result, AddResult::Added);
398 assert_eq!(mgr.size(), 1);
399 assert_eq!(mgr.new_count(), 1);
400 assert_eq!(mgr.tried_count(), 0);
401 }
402
403 #[test]
404 fn test_update_existing() {
405 let mut mgr = AddressManager::new();
406 mgr.add_address(addr(1, 2, 3, 4, 8333), 1, source(), 1000);
407
408 let result = mgr.add_address(addr(1, 2, 3, 4, 8333), 9, source(), 2000);
409 assert_eq!(result, AddResult::Updated);
410 assert_eq!(mgr.size(), 1); }
412
413 #[test]
414 fn test_reject_loopback() {
415 let mut mgr = AddressManager::new();
416 let result = mgr.add_address(
417 SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 8333)),
418 1,
419 source(),
420 1000,
421 );
422 assert_eq!(result, AddResult::Rejected);
423 assert_eq!(mgr.size(), 0);
424 }
425
426 #[test]
427 fn test_reject_unspecified() {
428 let mut mgr = AddressManager::new();
429 let result = mgr.add_address(
430 SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 8333)),
431 1,
432 source(),
433 1000,
434 );
435 assert_eq!(result, AddResult::Rejected);
436 }
437
438 #[test]
439 fn test_reject_zero_port() {
440 let mut mgr = AddressManager::new();
441 let result = mgr.add_address(addr(1, 2, 3, 4, 0), 1, source(), 1000);
442 assert_eq!(result, AddResult::Rejected);
443 }
444
445 #[test]
446 fn test_mark_good_moves_to_tried() {
447 let mut mgr = AddressManager::new();
448 let a = addr(1, 2, 3, 4, 8333);
449 mgr.add_address(a, 1, source(), 1000);
450 assert_eq!(mgr.new_count(), 1);
451 assert_eq!(mgr.tried_count(), 0);
452
453 mgr.mark_good(&a, 2000);
454 assert_eq!(mgr.new_count(), 0);
455 assert_eq!(mgr.tried_count(), 1);
456 }
457
458 #[test]
459 fn test_mark_attempt() {
460 let mut mgr = AddressManager::new();
461 let a = addr(1, 2, 3, 4, 8333);
462 mgr.add_address(a, 1, source(), 1000);
463
464 mgr.mark_attempt(&a, 1100);
465 mgr.mark_attempt(&a, 1200);
466
467 let info = mgr.addresses.get(&a).unwrap();
468 assert_eq!(info.attempts, 2);
469 }
470
471 #[test]
472 fn test_expire_old() {
473 let mut mgr = AddressManager::new();
474 let a = addr(1, 2, 3, 4, 8333);
475 mgr.add_address(a, 1, source(), 1000);
476
477 mgr.expire_old(1000 + MAX_ADDRESS_AGE - 1);
479 assert_eq!(mgr.size(), 1);
480
481 mgr.expire_old(1000 + MAX_ADDRESS_AGE);
483 assert_eq!(mgr.size(), 0);
484 }
485
486 #[test]
487 fn test_select_for_connection() {
488 let mut mgr = AddressManager::new();
489
490 for i in 1..=10u8 {
492 mgr.add_address(addr(1, 2, 3, i, 8333), 1, source(), 1000);
493 }
494
495 mgr.mark_good(&addr(1, 2, 3, 1, 8333), 2000);
497 mgr.mark_good(&addr(1, 2, 3, 2, 8333), 2000);
498
499 let selected = mgr.select_for_connection(3, 3000);
501 assert_eq!(selected.len(), 3);
502 assert!(
504 selected.contains(&addr(1, 2, 3, 1, 8333))
505 || selected.contains(&addr(1, 2, 3, 2, 8333))
506 );
507 }
508
509 #[test]
510 fn test_get_addr_response() {
511 let mut mgr = AddressManager::new();
512
513 for i in 1..=20u8 {
514 mgr.add_address(addr(1, 2, 3, i, 8333), 1, source(), 1000);
515 }
516
517 let response = mgr.get_addr_response(1000);
518 assert!(!response.is_empty());
520 assert!(response.len() <= MAX_ADDR_RESPONSE);
521 }
522
523 #[test]
524 fn test_remove_by_source() {
525 let mut mgr = AddressManager::new();
526 let src1 = IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1));
527 let src2 = IpAddr::V4(Ipv4Addr::new(10, 0, 0, 2));
528
529 mgr.add_address(addr(1, 2, 3, 1, 8333), 1, src1, 1000);
530 mgr.add_address(addr(1, 2, 3, 2, 8333), 1, src1, 1000);
531 mgr.add_address(addr(1, 2, 3, 3, 8333), 1, src2, 1000);
532
533 assert_eq!(mgr.size(), 3);
534
535 mgr.remove_by_source(&src1);
536 assert_eq!(mgr.size(), 1);
537
538 assert!(mgr.addresses.contains_key(&addr(1, 2, 3, 3, 8333)));
540 }
541
542 #[test]
543 fn test_eviction_on_new_table_full() {
544 let mut mgr = AddressManager::new();
545
546 for i in 0..MAX_NEW_ADDRESSES {
548 let a = i as u32;
549 let d = (a & 0xff) as u8;
550 let c = ((a >> 8) & 0xff) as u8;
551 let b = ((a >> 16) & 0xff) as u8;
552 let port = 8333 + (i as u16 % 100);
554 mgr.add_address(
555 addr(1 + b, c, d, ((i % 254) + 1) as u8, port),
556 1,
557 source(),
558 1000 + i as u64,
559 );
560 }
561
562 assert_eq!(mgr.new_count(), MAX_NEW_ADDRESSES);
563
564 let result = mgr.add_address(addr(99, 99, 99, 99, 8333), 1, source(), 5000);
566 assert_eq!(result, AddResult::Added);
567 assert_eq!(mgr.new_count(), MAX_NEW_ADDRESSES);
569 }
570}