use std::array::TryFromSliceError;
use std::convert::TryInto;
use std::net::SocketAddr;
use util::Error;
pub(super) trait SocketAddrExt {
fn encode(&self, buffer: &mut [u8]) -> Result<usize, Error>;
fn decode(buffer: &[u8]) -> Result<SocketAddr, Error>;
}
const IPV4_MARKER: u8 = 4;
const IPV4_ADDRESS_SIZE: usize = 7;
const IPV6_MARKER: u8 = 6;
const IPV6_ADDRESS_SIZE: usize = 27;
pub(super) const MAX_ADDR_SIZE: usize = IPV6_ADDRESS_SIZE;
impl SocketAddrExt for SocketAddr {
fn encode(&self, buffer: &mut [u8]) -> Result<usize, Error> {
use std::net::SocketAddr::{V4, V6};
if buffer.len() < MAX_ADDR_SIZE {
return Err(Error::ErrBufferShort);
}
match self {
V4(addr) => {
let marker = IPV4_MARKER;
let ip: [u8; 4] = addr.ip().octets();
let port: u16 = addr.port();
buffer[0] = marker;
buffer[1..5].copy_from_slice(&ip);
buffer[5..7].copy_from_slice(&port.to_le_bytes());
Ok(7)
}
V6(addr) => {
let marker = IPV6_MARKER;
let ip: [u8; 16] = addr.ip().octets();
let port: u16 = addr.port();
let flowinfo = addr.flowinfo();
let scope_id = addr.scope_id();
buffer[0] = marker;
buffer[1..17].copy_from_slice(&ip);
buffer[17..19].copy_from_slice(&port.to_le_bytes());
buffer[19..23].copy_from_slice(&flowinfo.to_le_bytes());
buffer[23..27].copy_from_slice(&scope_id.to_le_bytes());
Ok(MAX_ADDR_SIZE)
}
}
}
fn decode(buffer: &[u8]) -> Result<SocketAddr, Error> {
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6};
match buffer[0] {
IPV4_MARKER => {
if buffer.len() < IPV4_ADDRESS_SIZE {
return Err(Error::ErrBufferShort);
}
let ip_parts = &buffer[1..5];
let port = match &buffer[5..7].try_into() {
Err(_) => return Err(Error::ErrFailedToParseIpaddr),
Ok(input) => u16::from_le_bytes(*input),
};
let ip = Ipv4Addr::new(ip_parts[0], ip_parts[1], ip_parts[2], ip_parts[3]);
Ok(SocketAddr::V4(SocketAddrV4::new(ip, port)))
}
IPV6_MARKER => {
if buffer.len() < IPV6_ADDRESS_SIZE {
return Err(Error::ErrBufferShort);
}
fn helper(b: &[u8]) -> Result<&[u8; 16], TryFromSliceError> {
b.try_into()
}
let ip = match helper(&buffer[1..17]) {
Err(_) => return Err(Error::ErrFailedToParseIpaddr),
Ok(input) => Ipv6Addr::from(*input),
};
let port = match &buffer[17..19].try_into() {
Err(_) => return Err(Error::ErrFailedToParseIpaddr),
Ok(input) => u16::from_le_bytes(*input),
};
let flowinfo = match &buffer[19..23].try_into() {
Err(_) => return Err(Error::ErrFailedToParseIpaddr),
Ok(input) => u32::from_le_bytes(*input),
};
let scope_id = match &buffer[23..27].try_into() {
Err(_) => return Err(Error::ErrFailedToParseIpaddr),
Ok(input) => u32::from_le_bytes(*input),
};
Ok(SocketAddr::V6(SocketAddrV6::new(
ip, port, flowinfo, scope_id,
)))
}
_ => Err(Error::ErrFailedToParseIpaddr),
}
}
}
#[cfg(test)]
mod test {
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6};
use super::*;
#[test]
fn test_ipv4() {
let ip = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::from([56, 128, 35, 5]), 0x1234));
let mut buffer = [0_u8; MAX_ADDR_SIZE];
let encoded_len = ip.encode(&mut buffer);
assert_eq!(encoded_len, Ok(7));
assert_eq!(
&buffer[0..7],
&[IPV4_MARKER, 56, 128, 35, 5, 0x34, 0x12][..]
);
let decoded = SocketAddr::decode(&buffer);
assert_eq!(decoded, Ok(ip));
}
#[test]
fn test_ipv6() {
let ip = SocketAddr::V6(SocketAddrV6::new(
Ipv6Addr::from([
92, 114, 235, 3, 244, 64, 38, 111, 20, 100, 199, 241, 19, 174, 220, 123,
]),
0x1234,
0x12345678,
0x87654321,
));
let mut buffer = [0_u8; MAX_ADDR_SIZE];
let encoded_len = ip.encode(&mut buffer);
assert_eq!(encoded_len, Ok(27));
assert_eq!(
&buffer[0..27],
&[
IPV6_MARKER, 92,
114,
235,
3,
244,
64,
38,
111,
20,
100,
199,
241,
19,
174,
220,
123,
0x34,
0x12,
0x78,
0x56,
0x34,
0x12,
0x21,
0x43,
0x65,
0x87,
][..]
);
let decoded = SocketAddr::decode(&buffer);
assert_eq!(decoded, Ok(ip));
}
#[test]
fn test_encode_ipv4_with_short_buffer() {
let mut buffer = vec![0u8; IPV4_ADDRESS_SIZE - 1];
let ip = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::from([56, 128, 35, 5]), 0x1234));
let result = ip.encode(&mut buffer);
assert_eq!(result, Err(Error::ErrBufferShort));
}
#[test]
fn test_encode_ipv6_with_short_buffer() {
let mut buffer = vec![0u8; MAX_ADDR_SIZE - 1];
let ip = SocketAddr::V6(SocketAddrV6::new(
Ipv6Addr::from([
92, 114, 235, 3, 244, 64, 38, 111, 20, 100, 199, 241, 19, 174, 220, 123,
]),
0x1234,
0x12345678,
0x87654321,
));
let result = ip.encode(&mut buffer);
assert_eq!(result, Err(Error::ErrBufferShort));
}
#[test]
fn test_decode_ipv4_with_short_buffer() {
let buffer = vec![IPV4_MARKER, 0];
let result = SocketAddr::decode(&buffer);
assert_eq!(result, Err(Error::ErrBufferShort));
}
#[test]
fn test_decode_ipv6_with_short_buffer() {
let buffer = vec![IPV6_MARKER, 0];
let result = SocketAddr::decode(&buffer);
assert_eq!(result, Err(Error::ErrBufferShort));
}
}