use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
use crate::error::{Error, Result};
pub fn parse_compact_peers(data: &[u8]) -> Result<Vec<SocketAddr>> {
if !data.len().is_multiple_of(6) {
return Err(Error::InvalidResponse(format!(
"compact peers length {} is not a multiple of 6",
data.len()
)));
}
let mut peers = Vec::with_capacity(data.len() / 6);
for chunk in data.chunks_exact(6) {
let ip = Ipv4Addr::new(chunk[0], chunk[1], chunk[2], chunk[3]);
let port = u16::from_be_bytes([chunk[4], chunk[5]]);
peers.push(SocketAddr::V4(SocketAddrV4::new(ip, port)));
}
Ok(peers)
}
#[must_use]
pub fn encode_compact_peers(peers: &[SocketAddr]) -> Vec<u8> {
let mut buf = Vec::with_capacity(peers.len() * 6);
for peer in peers {
if let SocketAddr::V4(v4) = peer {
buf.extend_from_slice(&v4.ip().octets());
buf.extend_from_slice(&v4.port().to_be_bytes());
}
}
buf
}
pub fn parse_compact_peers6(data: &[u8]) -> Result<Vec<SocketAddr>> {
if !data.len().is_multiple_of(18) {
return Err(Error::InvalidResponse(format!(
"compact peers6 length {} is not a multiple of 18",
data.len()
)));
}
let mut peers = Vec::with_capacity(data.len() / 18);
for chunk in data.chunks_exact(18) {
let ip = Ipv6Addr::from(<[u8; 16]>::try_from(&chunk[..16]).unwrap());
let port = u16::from_be_bytes([chunk[16], chunk[17]]);
peers.push(SocketAddr::V6(SocketAddrV6::new(ip, port, 0, 0)));
}
Ok(peers)
}
#[must_use]
pub fn encode_compact_peers6(peers: &[SocketAddr]) -> Vec<u8> {
let mut buf = Vec::with_capacity(peers.len() * 18);
for peer in peers {
if let SocketAddr::V6(v6) = peer {
buf.extend_from_slice(&v6.ip().octets());
buf.extend_from_slice(&v6.port().to_be_bytes());
}
}
buf
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_single_peer() {
let data = [192, 168, 1, 1, 0x1A, 0xE1];
let peers = parse_compact_peers(&data).unwrap();
assert_eq!(peers.len(), 1);
assert_eq!(peers[0].to_string(), "192.168.1.1:6881");
}
#[test]
fn parse_multiple_peers() {
let mut data = Vec::new();
data.extend_from_slice(&[10, 0, 0, 1, 0x1F, 0x90]);
data.extend_from_slice(&[172, 16, 0, 1, 0x1A, 0xE1]);
let peers = parse_compact_peers(&data).unwrap();
assert_eq!(peers.len(), 2);
assert_eq!(peers[0].to_string(), "10.0.0.1:8080");
assert_eq!(peers[1].to_string(), "172.16.0.1:6881");
}
#[test]
fn parse_empty() {
let peers = parse_compact_peers(&[]).unwrap();
assert!(peers.is_empty());
}
#[test]
fn reject_invalid_length() {
assert!(parse_compact_peers(&[1, 2, 3, 4, 5]).is_err());
}
#[test]
fn encode_compact_peers_round_trip() {
let peers: Vec<SocketAddr> = vec![
"192.168.1.1:6881".parse().unwrap(),
"10.0.0.1:8080".parse().unwrap(),
];
let encoded = encode_compact_peers(&peers);
assert_eq!(encoded.len(), 12);
let decoded = parse_compact_peers(&encoded).unwrap();
assert_eq!(peers, decoded);
}
#[test]
fn encode_compact_peers_skips_ipv6() {
let peers: Vec<SocketAddr> = vec![
"192.168.1.1:6881".parse().unwrap(),
"[::1]:6881".parse().unwrap(),
];
let encoded = encode_compact_peers(&peers);
assert_eq!(encoded.len(), 6); }
#[test]
fn parse_single_peer6() {
let mut data = [0u8; 18];
data[15] = 1; data[16] = 0x1A;
data[17] = 0xE1; let peers = parse_compact_peers6(&data).unwrap();
assert_eq!(peers.len(), 1);
assert_eq!(peers[0], "[::1]:6881".parse::<SocketAddr>().unwrap());
}
#[test]
fn parse_multiple_peers6() {
let mut data = Vec::new();
let ip1: Ipv6Addr = "2001:db8::1".parse().unwrap();
data.extend_from_slice(&ip1.octets());
data.extend_from_slice(&8080u16.to_be_bytes());
let ip2: Ipv6Addr = "fe80::42".parse().unwrap();
data.extend_from_slice(&ip2.octets());
data.extend_from_slice(&6881u16.to_be_bytes());
let peers = parse_compact_peers6(&data).unwrap();
assert_eq!(peers.len(), 2);
assert_eq!(
peers[0],
"[2001:db8::1]:8080".parse::<SocketAddr>().unwrap()
);
assert_eq!(peers[1], "[fe80::42]:6881".parse::<SocketAddr>().unwrap());
}
#[test]
fn parse_empty_peers6() {
let peers = parse_compact_peers6(&[]).unwrap();
assert!(peers.is_empty());
}
#[test]
fn reject_invalid_length_peers6() {
assert!(parse_compact_peers6(&[0u8; 17]).is_err());
assert!(parse_compact_peers6(&[0u8; 19]).is_err());
}
#[test]
fn encode_compact_peers6_round_trip() {
let peers: Vec<SocketAddr> = vec![
"[2001:db8::1]:8080".parse().unwrap(),
"[::1]:6881".parse().unwrap(),
];
let encoded = encode_compact_peers6(&peers);
assert_eq!(encoded.len(), 36);
let decoded = parse_compact_peers6(&encoded).unwrap();
assert_eq!(peers, decoded);
}
#[test]
fn encode_compact_peers6_skips_ipv4() {
let peers: Vec<SocketAddr> = vec![
"[::1]:6881".parse().unwrap(),
"192.168.1.1:6881".parse().unwrap(),
];
let encoded = encode_compact_peers6(&peers);
assert_eq!(encoded.len(), 18); }
}