use super::{
VERSION,
types::{
Address,
AuthenticationMethod,
CommandType,
Reply,
},
};
use crate::{
DecodeError,
DecodeStatus,
EncodeError,
Message,
};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ClientGreeting {
pub methods: Box<[AuthenticationMethod]>,
}
impl Message for ClientGreeting {
fn encoded_len(&self) -> usize {
self.methods.len().saturating_add(2)
}
fn encode(&self, buffer: &mut Vec<u8>) -> Result<(), EncodeError> {
let count = u8::try_from(self.methods.len())
.map_err(|_error| EncodeError::TooLong("more than 255 authentication methods"))?;
buffer.reserve(self.encoded_len());
buffer.push(VERSION);
buffer.push(count);
buffer.extend(self.methods.iter().map(|&method| u8::from(method)));
Ok(())
}
fn decode(source: &[u8]) -> Result<DecodeStatus<(Self, usize)>, DecodeError> {
let Some((&version, after_version)) = source.split_first() else {
return Ok(DecodeStatus::Partial);
};
if version != VERSION {
return Err(DecodeError::InvalidVersion {
expected: VERSION,
actual: version,
});
}
let Some((&count, rest)) = after_version.split_first() else {
return Ok(DecodeStatus::Partial);
};
let count = usize::from(count);
let Some(method_bytes) = rest.get(.. count) else {
return Ok(DecodeStatus::Partial);
};
let methods = method_bytes
.iter()
.map(|&byte| AuthenticationMethod::from(byte))
.collect::<Vec<_>>()
.into_boxed_slice();
Ok(DecodeStatus::Complete((
Self {
methods,
},
count.saturating_add(2),
)))
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ServerChoice {
pub method: AuthenticationMethod,
}
impl Message for ServerChoice {
fn encoded_len(&self) -> usize {
2
}
fn encode(&self, buffer: &mut Vec<u8>) -> Result<(), EncodeError> {
buffer.reserve(2);
buffer.push(VERSION);
buffer.push(u8::from(self.method));
Ok(())
}
fn decode(source: &[u8]) -> Result<DecodeStatus<(Self, usize)>, DecodeError> {
let Some((&version, after_version)) = source.split_first() else {
return Ok(DecodeStatus::Partial);
};
if version != VERSION {
return Err(DecodeError::InvalidVersion {
expected: VERSION,
actual: version,
});
}
let Some((&method, _rest)) = after_version.split_first() else {
return Ok(DecodeStatus::Partial);
};
Ok(DecodeStatus::Complete((
Self {
method: AuthenticationMethod::from(method),
},
2,
)))
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Request {
pub command: CommandType,
pub address: Address,
pub port: u16,
}
impl Message for Request {
fn encoded_len(&self) -> usize {
self.address.encoded_len().saturating_add(5)
}
fn encode(&self, buffer: &mut Vec<u8>) -> Result<(), EncodeError> {
buffer.reserve(self.encoded_len());
buffer.push(VERSION);
buffer.push(u8::from(self.command));
buffer.push(0x00); self.address.encode_into(buffer)?;
buffer.extend_from_slice(&self.port.to_be_bytes());
Ok(())
}
fn decode(source: &[u8]) -> Result<DecodeStatus<(Self, usize)>, DecodeError> {
let Some((&version, after_version)) = source.split_first() else {
return Ok(DecodeStatus::Partial);
};
if version != VERSION {
return Err(DecodeError::InvalidVersion {
expected: VERSION,
actual: version,
});
}
let Some((&command, after_command)) = after_version.split_first() else {
return Ok(DecodeStatus::Partial);
};
let Some((&reserved, rest)) = after_command.split_first() else {
return Ok(DecodeStatus::Partial);
};
if reserved != 0x00 {
return Err(DecodeError::Malformed("reserved byte is not zero"));
}
let (address, consumed) = match Address::decode_from(rest)? {
| DecodeStatus::Complete(complete) => complete,
| DecodeStatus::Partial => return Ok(DecodeStatus::Partial),
};
let Some(after_address) = rest.get(consumed ..) else {
return Ok(DecodeStatus::Partial);
};
let Some(&[port_high, port_low]) = after_address.first_chunk::<2>() else {
return Ok(DecodeStatus::Partial);
};
Ok(DecodeStatus::Complete((
Self {
command: CommandType::from(command),
address,
port: u16::from_be_bytes([port_high, port_low]),
},
consumed.saturating_add(5),
)))
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Response {
pub reply: Reply,
pub address: Address,
pub port: u16,
}
impl Response {
pub const COMMAND_NOT_SUPPORTED: Self = Self::error_reply(Reply::COMMAND_NOT_SUPPORTED);
pub const HOST_UNREACHABLE: Self = Self::error_reply(Reply::HOST_UNREACHABLE);
#[must_use]
pub const fn error_reply(reply: Reply) -> Self {
Self {
reply,
address: Address::Ipv4(std::net::Ipv4Addr::UNSPECIFIED),
port: 0,
}
}
}
impl Message for Response {
fn encoded_len(&self) -> usize {
self.address.encoded_len().saturating_add(5)
}
fn encode(&self, buffer: &mut Vec<u8>) -> Result<(), EncodeError> {
buffer.reserve(self.encoded_len());
buffer.push(VERSION);
buffer.push(u8::from(self.reply));
buffer.push(0x00); self.address.encode_into(buffer)?;
buffer.extend_from_slice(&self.port.to_be_bytes());
Ok(())
}
fn decode(source: &[u8]) -> Result<DecodeStatus<(Self, usize)>, DecodeError> {
let Some((&version, after_version)) = source.split_first() else {
return Ok(DecodeStatus::Partial);
};
if version != VERSION {
return Err(DecodeError::InvalidVersion {
expected: VERSION,
actual: version,
});
}
let Some((&reply, after_reply)) = after_version.split_first() else {
return Ok(DecodeStatus::Partial);
};
let Some((&reserved, rest)) = after_reply.split_first() else {
return Ok(DecodeStatus::Partial);
};
if reserved != 0x00 {
return Err(DecodeError::Malformed("reserved byte is not zero"));
}
let (address, consumed) = match Address::decode_from(rest)? {
| DecodeStatus::Complete(complete) => complete,
| DecodeStatus::Partial => return Ok(DecodeStatus::Partial),
};
let Some(after_address) = rest.get(consumed ..) else {
return Ok(DecodeStatus::Partial);
};
let Some(&[port_high, port_low]) = after_address.first_chunk::<2>() else {
return Ok(DecodeStatus::Partial);
};
Ok(DecodeStatus::Complete((
Self {
reply: Reply::from(reply),
address,
port: u16::from_be_bytes([port_high, port_low]),
},
consumed.saturating_add(5),
)))
}
}