use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
use bytes::{Buf, BufMut};
use crate::coding::{self, BufExt, BufMutExt};
use crate::VarInt;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AddAddress {
pub sequence_number: VarInt,
pub address: SocketAddr,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PunchMeNow {
pub round: VarInt,
pub paired_with_sequence_number: VarInt,
pub address: SocketAddr,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RemoveAddress {
pub sequence_number: VarInt,
}
impl AddAddress {
pub fn decode<B: Buf>(buf: &mut B, is_ipv6: bool) -> coding::Result<Self> {
let sequence_number = buf.get_var()?;
let ip = if is_ipv6 {
if buf.remaining() < 16 {
return Err(coding::UnexpectedEnd);
}
let mut octets = [0u8; 16];
buf.copy_to_slice(&mut octets);
IpAddr::V6(Ipv6Addr::from(octets))
} else {
if buf.remaining() < 4 {
return Err(coding::UnexpectedEnd);
}
let mut octets = [0u8; 4];
buf.copy_to_slice(&mut octets);
IpAddr::V4(Ipv4Addr::from(octets))
};
if buf.remaining() < 2 {
return Err(coding::UnexpectedEnd);
}
let port = buf.get_u16();
Ok(Self {
sequence_number,
address: SocketAddr::new(ip, port),
})
}
pub fn encode<B: BufMut>(&self, buf: &mut B) {
buf.write_var_or_debug_assert(self.sequence_number.into_inner());
match self.address.ip() {
IpAddr::V4(ipv4) => {
buf.put_slice(&ipv4.octets());
},
IpAddr::V6(ipv6) => {
buf.put_slice(&ipv6.octets());
},
}
buf.put_u16(self.address.port());
}
}
impl PunchMeNow {
pub fn decode<B: Buf>(buf: &mut B, is_ipv6: bool) -> coding::Result<Self> {
let round = buf.get_var()?;
let paired_with_sequence_number = buf.get_var()?;
let ip = if is_ipv6 {
if buf.remaining() < 16 {
return Err(coding::UnexpectedEnd);
}
let mut octets = [0u8; 16];
buf.copy_to_slice(&mut octets);
IpAddr::V6(Ipv6Addr::from(octets))
} else {
if buf.remaining() < 4 {
return Err(coding::UnexpectedEnd);
}
let mut octets = [0u8; 4];
buf.copy_to_slice(&mut octets);
IpAddr::V4(Ipv4Addr::from(octets))
};
if buf.remaining() < 2 {
return Err(coding::UnexpectedEnd);
}
let port = buf.get_u16();
Ok(Self {
round,
paired_with_sequence_number,
address: SocketAddr::new(ip, port),
})
}
pub fn encode<B: BufMut>(&self, buf: &mut B) {
buf.write_var_or_debug_assert(self.round.into_inner());
buf.write_var_or_debug_assert(self.paired_with_sequence_number.into_inner());
match self.address.ip() {
IpAddr::V4(ipv4) => {
buf.put_slice(&ipv4.octets());
},
IpAddr::V6(ipv6) => {
buf.put_slice(&ipv6.octets());
},
}
buf.put_u16(self.address.port());
}
}
impl RemoveAddress {
pub fn decode<B: Buf>(buf: &mut B) -> coding::Result<Self> {
let sequence_number = buf.get_var()?;
Ok(Self { sequence_number })
}
pub fn encode<B: BufMut>(&self, buf: &mut B) {
buf.write_var_or_debug_assert(self.sequence_number.into_inner());
}
}
#[cfg(test)]
mod tests {
use super::*;
use bytes::BytesMut;
#[test]
fn test_add_address_ipv4_roundtrip() {
let frame = AddAddress {
sequence_number: VarInt::from_u32(42),
address: "192.168.1.1:8080".parse().unwrap(),
};
let mut buf = BytesMut::new();
frame.encode(&mut buf);
let decoded = AddAddress::decode(&mut buf.freeze(), false).unwrap();
assert_eq!(frame, decoded);
}
#[test]
fn test_add_address_ipv6_roundtrip() {
let frame = AddAddress {
sequence_number: VarInt::from_u32(123),
address: "[2001:db8::1]:9000".parse().unwrap(),
};
let mut buf = BytesMut::new();
frame.encode(&mut buf);
let decoded = AddAddress::decode(&mut buf.freeze(), true).unwrap();
assert_eq!(frame, decoded);
}
#[test]
fn test_punch_me_now_roundtrip() {
let frame = PunchMeNow {
round: VarInt::from_u32(5),
paired_with_sequence_number: VarInt::from_u32(42),
address: "10.0.0.1:1234".parse().unwrap(),
};
let mut buf = BytesMut::new();
frame.encode(&mut buf);
let decoded = PunchMeNow::decode(&mut buf.freeze(), false).unwrap();
assert_eq!(frame, decoded);
}
#[test]
fn test_remove_address_roundtrip() {
let frame = RemoveAddress {
sequence_number: VarInt::from_u32(999),
};
let mut buf = BytesMut::new();
frame.encode(&mut buf);
let decoded = RemoveAddress::decode(&mut buf.freeze()).unwrap();
assert_eq!(frame, decoded);
}
}