use std::convert::TryFrom;
use std::io::{Error, ErrorKind};
use std::mem::size_of;
use std::time::Duration;
use crate::encodings::{Context, OctetString, SearchRangeList, VarBindList, ID};
use crate::{bytes_to_u16, bytes_to_u32, u16_to_bytes, u32_to_bytes, ByteOrder};
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] pub struct Header {
pub version: u8,
pub ty: Type, pub flags: u8,
pub session_id: u32,
pub transaction_id: u32,
pub packet_id: u32,
pub payload_length: u32, }
pub const INSTANCE_REGISTRATION: u8 = 0;
pub const NEW_INDEX: u8 = 1;
pub const ANY_INDEX: u8 = 2;
pub const NON_DEFAULT_CONTEXT: u8 = 3;
pub const NETWORK_BYTE_ORDER: u8 = 4;
fn is_set(flags: u8, mask: u8) -> bool {
flags & mask == mask
}
const HEADER_SIZE: usize = 20;
fn header_byte_order(flags: u8) -> ByteOrder {
match is_set(flags, 1 << NETWORK_BYTE_ORDER) {
true => ByteOrder::BigEndian,
false => ByteOrder::LittleEndian,
}
}
fn context_from_bytes(header: &Header, b: &[u8]) -> Result<Option<Context>, Error> {
let bo = header.byte_order();
match is_set(header.flags, 1 << NON_DEFAULT_CONTEXT) {
false => Ok(None),
true => Ok(Some(Context::from_bytes(b, &bo)?)),
}
}
impl Header {
pub fn new(ty: Type) -> Self {
Self {
version: 1,
ty,
flags: 0,
session_id: 0,
transaction_id: 0,
packet_id: 0,
payload_length: 0,
}
}
fn byte_order(&self) -> ByteOrder {
header_byte_order(self.flags)
}
pub fn to_bytes(&self) -> Vec<u8> {
let mut result = Vec::with_capacity(HEADER_SIZE);
result.extend(&[
self.version,
self.ty.to_byte(),
self.flags,
0,
]);
let bo = self.byte_order();
result.extend(&u32_to_bytes(self.session_id, &bo));
result.extend(&u32_to_bytes(self.transaction_id, &bo));
result.extend(&u32_to_bytes(self.packet_id, &bo));
result.extend(&u32_to_bytes(self.payload_length, &bo));
result
}
pub fn from_bytes(b: &[u8]) -> Result<Self, Error> {
if b.len() < HEADER_SIZE {
return Err(Error::from(ErrorKind::InvalidData));
}
let (version, ty, flags) = (b[0], Type::from_byte(b[1])?, b[2]);
let bo = header_byte_order(flags);
let session_id = bytes_to_u32(&b[4..], &bo)?;
let transaction_id = bytes_to_u32(&b[8..], &bo)?;
let packet_id = bytes_to_u32(&b[12..], &bo)?;
let payload_length = bytes_to_u32(&b[16..], &bo)?;
Ok(Self {
version,
ty,
flags,
session_id,
transaction_id,
packet_id,
payload_length,
})
}
fn byte_size(&self) -> usize {
HEADER_SIZE
}
fn set_payload_len(&mut self, len: usize) -> Result<(), Error> {
self.payload_length = u32::try_from(len).map_err(|_| ErrorKind::InvalidData)?;
Ok(())
}
}
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub struct Open {
pub header: Header,
pub timeout: Duration, pub id: ID,
pub descr: OctetString,
}
impl Default for Open {
fn default() -> Self {
Self {
header: Header::new(Type::Open),
timeout: Duration::new(0, 0),
id: ID::default(),
descr: OctetString::default(),
}
}
}
impl Open {
pub fn new(id: ID, descr: &str) -> Self {
Open {
id,
descr: OctetString(descr.to_string()),
..Default::default()
}
}
pub fn to_bytes(&mut self) -> Result<Vec<u8>, Error> {
let mut result = Vec::new();
let mut payload = Vec::new();
let bo = self.header.byte_order();
let timeout_secs =
u8::try_from(self.timeout.as_secs()).map_err(|_| ErrorKind::InvalidData)?;
payload.push(timeout_secs);
payload.extend(&[0, 0, 0]); payload.extend(self.id.to_bytes(&bo));
payload.extend(self.descr.to_bytes(&bo)?);
self.header.set_payload_len(payload.len())?;
result.extend(self.header.to_bytes());
result.extend(payload);
Ok(result)
}
pub fn from_bytes(b: &[u8]) -> Result<Self, Error> {
let header = Header::from_bytes(b)?;
let bo = header.byte_order();
let mut b = b.get(header.byte_size()..).ok_or(ErrorKind::InvalidData)?;
if b.len() < size_of::<u32>() {
return Err(Error::from(ErrorKind::InvalidData));
}
let timeout = Duration::from_secs(b[0] as u64);
b = b.get(4..).ok_or(ErrorKind::InvalidData)?;
let id = ID::from_bytes(b, &bo)?;
b = b.get(id.byte_size()..).ok_or(ErrorKind::InvalidData)?;
let descr = OctetString::from_bytes(b, &bo)?;
Ok(Self {
header,
timeout,
id,
descr,
})
}
}
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub struct Close {
pub header: Header,
pub reason: CloseReason,
}
impl Default for Close {
fn default() -> Self {
Self {
header: Header::new(Type::Close),
reason: CloseReason::Other,
}
}
}
impl Close {
pub fn new(reason: CloseReason) -> Self {
Self {
reason,
..Default::default()
}
}
pub fn to_bytes(&mut self) -> Result<Vec<u8>, Error> {
let mut result = Vec::new();
self.header.payload_length = 4;
result.extend(self.header.to_bytes());
result.push(self.reason.to_byte());
result.extend(&[0, 0, 0]);
Ok(result)
}
pub fn from_bytes(b: &[u8]) -> Result<Self, Error> {
let header = Header::from_bytes(b)?;
let b = b.get(header.byte_size()..).ok_or(ErrorKind::InvalidData)?;
if b.len() < size_of::<u8>() {
return Err(Error::from(ErrorKind::InvalidData));
}
let reason = CloseReason::from_byte(b[0])?;
Ok(Self { header, reason })
}
}
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] pub struct Register {
pub header: Header,
pub context: Option<Context>,
pub timeout: Duration, pub priority: u8,
pub range_subid: u8,
pub subtree: ID,
pub upper_bound: Option<u32>, }
impl Register {
pub fn new(subtree: ID) -> Self {
let header = Header::new(Type::Register);
Self {
header,
context: None,
timeout: Duration::new(0, 0), priority: 0, range_subid: 0,
subtree,
upper_bound: None,
}
}
pub fn to_bytes(&mut self) -> Result<Vec<u8>, Error> {
let mut result = Vec::new();
let mut payload = Vec::new();
let bo = self.header.byte_order();
if let Some(c) = &self.context {
payload.extend(c.0.to_bytes(&bo)?);
};
let timeout_secs =
u8::try_from(self.timeout.as_secs()).map_err(|_| ErrorKind::InvalidData)?;
payload.extend(&[
timeout_secs,
self.priority,
self.range_subid,
0,
]);
payload.extend(self.subtree.to_bytes(&bo));
if let Some(u) = &self.upper_bound {
payload.extend(&u32_to_bytes(*u, &bo));
};
self.header.set_payload_len(payload.len())?;
result.extend(self.header.to_bytes());
result.extend(payload);
Ok(result)
}
pub fn from_bytes(b: &[u8]) -> Result<Self, Error> {
let header = Header::from_bytes(b)?;
let bo = header.byte_order();
let mut b = b.get(header.byte_size()..).ok_or(ErrorKind::InvalidData)?;
let context = context_from_bytes(&header, b)?;
if let Some(c) = &context {
b = b.get(c.byte_size()..).ok_or(ErrorKind::InvalidData)?;
}
if b.len() < size_of::<u32>() {
return Err(Error::from(ErrorKind::InvalidData));
}
let (timeout, priority, range_subid) = (Duration::from_secs(b[0] as u64), b[1], b[2]);
b = b.get(4..).ok_or(ErrorKind::InvalidData)?;
let subtree = ID::from_bytes(b, &bo)?;
b = b.get(subtree.byte_size()..).ok_or(ErrorKind::InvalidData)?;
let upper_bound = if range_subid != 0 {
Some(bytes_to_u32(b, &bo)?)
} else {
None
};
Ok(Self {
header,
context,
timeout,
priority,
range_subid,
subtree,
upper_bound,
})
}
}
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] pub struct Unregister {
pub header: Header,
pub context: Option<Context>,
pub priority: u8,
pub range_subid: u8,
pub subtree: ID,
pub upper_bound: Option<u32>,
}
impl Unregister {
pub fn new(subtree: ID, priority: u8) -> Self {
let header = Header::new(Type::Unregister);
Self {
header,
context: None,
priority,
range_subid: 0,
subtree,
upper_bound: None,
}
}
pub fn to_bytes(&mut self) -> Result<Vec<u8>, Error> {
let mut result = Vec::new();
let mut payload = Vec::new();
let bo = self.header.byte_order();
if let Some(c) = &self.context {
payload.extend(c.0.to_bytes(&bo)?);
};
payload.extend(&[
0,
self.priority,
self.range_subid,
0,
]);
payload.extend(self.subtree.to_bytes(&bo));
if let Some(u) = &self.upper_bound {
payload.extend(&u32_to_bytes(*u, &bo));
};
self.header.set_payload_len(payload.len())?;
result.extend(self.header.to_bytes());
result.extend(payload);
Ok(result)
}
pub fn from_bytes(b: &[u8]) -> Result<Self, Error> {
let header = Header::from_bytes(b)?;
let bo = header.byte_order();
let mut b = b.get(header.byte_size()..).ok_or(ErrorKind::InvalidData)?;
let context = context_from_bytes(&header, b)?;
if let Some(c) = &context {
b = b.get(c.byte_size()..).ok_or(ErrorKind::InvalidData)?;
}
if b.len() < size_of::<u32>() {
return Err(Error::from(ErrorKind::InvalidData));
}
let (priority, range_subid) = ( b[1], b[2]);
b = b.get(4..).ok_or(ErrorKind::InvalidData)?;
let subtree = ID::from_bytes(b, &bo)?;
b = b.get(subtree.byte_size()..).ok_or(ErrorKind::InvalidData)?;
let upper_bound = if range_subid != 0 {
Some(bytes_to_u32(b, &bo)?)
} else {
None
};
Ok(Self {
header,
context,
priority,
range_subid,
subtree,
upper_bound,
})
}
}
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] pub struct Get {
pub header: Header,
pub context: Option<Context>,
pub sr: SearchRangeList,
}
fn get_alike_from_bytes(b: &[u8]) -> Result<(Header, Option<Context>, SearchRangeList), Error> {
let header = Header::from_bytes(b)?;
let bo = header.byte_order();
let mut b = b.get(header.byte_size()..).ok_or(ErrorKind::InvalidData)?;
let context = context_from_bytes(&header, b)?;
if let Some(c) = &context {
b = b.get(c.byte_size()..).ok_or(ErrorKind::InvalidData)?;
}
let sr = SearchRangeList::from_bytes(b, &bo)?;
Ok((header, context, sr))
}
impl Get {
pub fn new(sr: SearchRangeList) -> Self {
let header = Header::new(Type::Get);
Self {
header,
context: None,
sr,
}
}
pub fn to_bytes(&mut self) -> Result<Vec<u8>, Error> {
let mut result = Vec::new();
let mut payload = Vec::new();
let bo = self.header.byte_order();
if let Some(c) = &self.context {
payload.extend(c.0.to_bytes(&bo)?);
};
payload.extend(self.sr.to_bytes(&bo));
self.header.set_payload_len(payload.len())?;
result.extend(self.header.to_bytes());
result.extend(payload);
Ok(result)
}
pub fn from_bytes(b: &[u8]) -> Result<Self, Error> {
let (header, context, sr) = get_alike_from_bytes(b)?;
Ok(Self {
header,
context,
sr,
})
}
}
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] pub struct GetNext {
pub header: Header,
pub context: Option<Context>,
pub sr: SearchRangeList,
}
impl GetNext {
pub fn new(sr: SearchRangeList) -> Self {
let header = Header::new(Type::GetNext);
Self {
header,
context: None,
sr,
}
}
pub fn to_bytes(&mut self) -> Result<Vec<u8>, Error> {
let mut result = Vec::new();
let mut payload = Vec::new();
let bo = self.header.byte_order();
if let Some(c) = &self.context {
payload.extend(c.0.to_bytes(&bo)?);
};
payload.extend(self.sr.to_bytes(&bo));
self.header.set_payload_len(payload.len())?;
result.extend(self.header.to_bytes());
result.extend(payload);
Ok(result)
}
pub fn from_bytes(b: &[u8]) -> Result<Self, Error> {
let (header, context, sr) = get_alike_from_bytes(b)?;
Ok(Self {
header,
context,
sr,
})
}
}
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] pub struct GetBulk {
pub header: Header,
pub context: Option<Context>,
pub non_repeaters: u16,
pub max_repetitions: u16,
pub sr: SearchRangeList,
}
impl GetBulk {
pub fn new(sr: SearchRangeList) -> Self {
let header = Header::new(Type::GetBulk);
Self {
header,
context: None,
non_repeaters: 0,
max_repetitions: 0,
sr,
}
}
pub fn to_bytes(&mut self) -> Result<Vec<u8>, Error> {
let mut result = Vec::new();
let mut payload = Vec::new();
let bo = self.header.byte_order();
if let Some(c) = &self.context {
payload.extend(c.0.to_bytes(&bo)?);
};
payload.extend(&u16_to_bytes(self.non_repeaters, &bo));
payload.extend(&u16_to_bytes(self.max_repetitions, &bo));
payload.extend(self.sr.to_bytes(&bo));
self.header.set_payload_len(payload.len())?;
result.extend(self.header.to_bytes());
result.extend(payload);
Ok(result)
}
pub fn from_bytes(b: &[u8]) -> Result<Self, Error> {
let header = Header::from_bytes(b)?;
let bo = header.byte_order();
let mut b = b.get(header.byte_size()..).ok_or(ErrorKind::InvalidData)?;
let context = context_from_bytes(&header, b)?;
if let Some(c) = &context {
b = b.get(c.byte_size()..).ok_or(ErrorKind::InvalidData)?;
}
if b.len() < size_of::<u32>() {
return Err(Error::from(ErrorKind::InvalidData));
}
let (non_repeaters, max_repetitions) = (bytes_to_u16(b, &bo)?, bytes_to_u16(&b[2..], &bo)?);
b = b.get(4..).ok_or(ErrorKind::InvalidData)?;
let sr = SearchRangeList::from_bytes(b, &bo)?;
Ok(Self {
header,
context,
non_repeaters,
max_repetitions,
sr,
})
}
}
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] pub struct TestSet {
pub header: Header,
pub context: Option<Context>,
pub vb: VarBindList,
}
fn testset_alike_from_bytes(b: &[u8]) -> Result<(Header, Option<Context>, VarBindList), Error> {
let header = Header::from_bytes(b)?;
let bo = header.byte_order();
let mut b = b.get(header.byte_size()..).ok_or(ErrorKind::InvalidData)?;
let context = context_from_bytes(&header, b)?;
if let Some(c) = &context {
b = b.get(c.byte_size()..).ok_or(ErrorKind::InvalidData)?;
}
let vb = VarBindList::from_bytes(b, &bo)?;
Ok((header, context, vb))
}
impl TestSet {
pub fn new(vb: VarBindList) -> Self {
let header = Header::new(Type::TestSet);
Self {
header,
context: None,
vb,
}
}
pub fn to_bytes(&mut self) -> Result<Vec<u8>, Error> {
let mut result = Vec::new();
let mut payload = Vec::new();
let bo = self.header.byte_order();
if let Some(c) = &self.context {
payload.extend(c.0.to_bytes(&bo)?);
};
payload.extend(self.vb.to_bytes(&bo)?);
self.header.set_payload_len(payload.len())?;
result.extend(self.header.to_bytes());
result.extend(payload);
Ok(result)
}
pub fn from_bytes(b: &[u8]) -> Result<Self, Error> {
let (header, context, vb) = testset_alike_from_bytes(b)?;
Ok(Self {
header,
context,
vb,
})
}
}
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] pub struct Notify {
pub header: Header,
pub context: Option<Context>,
pub vb: VarBindList,
}
impl Notify {
pub fn new(vb: VarBindList) -> Self {
let header = Header::new(Type::Notify);
Self {
header,
context: None,
vb,
}
}
pub fn to_bytes(&mut self) -> Result<Vec<u8>, Error> {
let mut result = Vec::new();
let mut payload = Vec::new();
let bo = self.header.byte_order();
if let Some(c) = &self.context {
payload.extend(c.0.to_bytes(&bo)?);
};
payload.extend(self.vb.to_bytes(&bo)?);
self.header.set_payload_len(payload.len())?;
result.extend(self.header.to_bytes());
result.extend(payload);
Ok(result)
}
pub fn from_bytes(b: &[u8]) -> Result<Self, Error> {
let (header, context, vb) = testset_alike_from_bytes(b)?;
Ok(Self {
header,
context,
vb,
})
}
}
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] pub struct IndexAllocate {
pub header: Header,
pub context: Option<Context>,
pub vb: VarBindList,
}
impl IndexAllocate {
pub fn new(vb: VarBindList) -> Self {
let header = Header::new(Type::IndexAllocate);
Self {
header,
context: None,
vb,
}
}
pub fn to_bytes(&mut self) -> Result<Vec<u8>, Error> {
let mut result = Vec::new();
let mut payload = Vec::new();
let bo = self.header.byte_order();
if let Some(c) = &self.context {
payload.extend(c.0.to_bytes(&bo)?);
};
payload.extend(self.vb.to_bytes(&bo)?);
self.header.set_payload_len(payload.len())?;
result.extend(self.header.to_bytes());
result.extend(payload);
Ok(result)
}
pub fn from_bytes(b: &[u8]) -> Result<Self, Error> {
let (header, context, vb) = testset_alike_from_bytes(b)?;
Ok(Self {
header,
context,
vb,
})
}
}
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] pub struct IndexDeallocate {
pub header: Header,
pub context: Option<Context>,
pub vb: VarBindList,
}
impl IndexDeallocate {
pub fn new(vb: VarBindList) -> Self {
let header = Header::new(Type::IndexDeallocate);
Self {
header,
context: None,
vb,
}
}
pub fn to_bytes(&mut self) -> Result<Vec<u8>, Error> {
let mut result = Vec::new();
let mut payload = Vec::new();
let bo = self.header.byte_order();
if let Some(c) = &self.context {
payload.extend(c.0.to_bytes(&bo)?);
};
payload.extend(self.vb.to_bytes(&bo)?);
self.header.set_payload_len(payload.len())?;
result.extend(self.header.to_bytes());
result.extend(payload);
Ok(result)
}
pub fn from_bytes(b: &[u8]) -> Result<Self, Error> {
let (header, context, vb) = testset_alike_from_bytes(b)?;
Ok(Self {
header,
context,
vb,
})
}
}
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub struct CommitSet {
pub header: Header,
}
impl Default for CommitSet {
fn default() -> Self {
Self {
header: Header::new(Type::CommitSet),
}
}
}
impl CommitSet {
pub fn new() -> Self {
Self::default()
}
pub fn to_bytes(&mut self) -> Result<Vec<u8>, Error> {
Ok(self.header.to_bytes())
}
pub fn from_bytes(b: &[u8]) -> Result<Self, Error> {
Ok(Self {
header: Header::from_bytes(b)?,
})
}
}
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub struct UndoSet {
pub header: Header,
}
impl Default for UndoSet {
fn default() -> Self {
Self {
header: Header::new(Type::UndoSet),
}
}
}
impl UndoSet {
pub fn new() -> Self {
Self::default()
}
pub fn to_bytes(&mut self) -> Result<Vec<u8>, Error> {
Ok(self.header.to_bytes())
}
pub fn from_bytes(b: &[u8]) -> Result<Self, Error> {
Ok(Self {
header: Header::from_bytes(b)?,
})
}
}
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub struct CleanupSet {
pub header: Header,
}
impl Default for CleanupSet {
fn default() -> Self {
Self {
header: Header::new(Type::CleanupSet),
}
}
}
impl CleanupSet {
pub fn new() -> Self {
Self::default()
}
pub fn to_bytes(&mut self) -> Result<Vec<u8>, Error> {
Ok(self.header.to_bytes())
}
pub fn from_bytes(b: &[u8]) -> Result<Self, Error> {
Ok(Self {
header: Header::from_bytes(b)?,
})
}
}
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub struct Ping {
pub header: Header,
pub context: Option<Context>,
}
impl Default for Ping {
fn default() -> Self {
Self {
header: Header::new(Type::Ping),
context: None,
}
}
}
impl Ping {
pub fn new() -> Self {
Self::default()
}
pub fn to_bytes(&mut self) -> Result<Vec<u8>, Error> {
let mut result = Vec::new();
let mut payload = Vec::new();
let bo = self.header.byte_order();
if let Some(c) = &self.context {
payload.extend(c.0.to_bytes(&bo)?);
};
self.header.set_payload_len(payload.len())?;
result.extend(self.header.to_bytes());
result.extend(payload);
Ok(result)
}
pub fn from_bytes(b: &[u8]) -> Result<Self, Error> {
let header = Header::from_bytes(b)?;
let b = b.get(header.byte_size()..).ok_or(ErrorKind::InvalidData)?;
let context = context_from_bytes(&header, b)?;
Ok(Self { header, context })
}
}
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] pub struct AddAgentCaps {
pub header: Header,
pub context: Option<Context>,
pub id: ID,
pub descr: OctetString,
}
impl AddAgentCaps {
pub fn new(id: ID, descr: &str) -> Self {
let header = Header::new(Type::AddAgentCaps);
let descr = OctetString(descr.to_string());
Self {
header,
context: None,
id,
descr,
}
}
pub fn to_bytes(&mut self) -> Result<Vec<u8>, Error> {
let mut result = Vec::new();
let mut payload = Vec::new();
let bo = self.header.byte_order();
if let Some(c) = &self.context {
payload.extend(c.0.to_bytes(&bo)?);
};
payload.extend(self.id.to_bytes(&bo));
payload.extend(self.descr.to_bytes(&bo)?);
self.header.set_payload_len(payload.len())?;
result.extend(self.header.to_bytes());
result.extend(payload);
Ok(result)
}
pub fn from_bytes(b: &[u8]) -> Result<Self, Error> {
let header = Header::from_bytes(b)?;
let bo = header.byte_order();
let mut b = b.get(header.byte_size()..).ok_or(ErrorKind::InvalidData)?;
let context = context_from_bytes(&header, b)?;
if let Some(c) = &context {
b = b.get(c.byte_size()..).ok_or(ErrorKind::InvalidData)?;
}
let id = ID::from_bytes(b, &bo)?;
b = b.get(id.byte_size()..).ok_or(ErrorKind::InvalidData)?;
let descr = OctetString::from_bytes(b, &bo)?;
Ok(Self {
header,
context,
id,
descr,
})
}
}
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] pub struct RemoveAgentCaps {
pub header: Header,
pub context: Option<Context>,
pub id: ID,
}
impl RemoveAgentCaps {
pub fn new(id: ID) -> Self {
let header = Header::new(Type::RemoveAgentCaps);
Self {
header,
context: None,
id,
}
}
pub fn to_bytes(&mut self) -> Result<Vec<u8>, Error> {
let mut result = Vec::new();
let mut payload = Vec::new();
let bo = self.header.byte_order();
if let Some(c) = &self.context {
payload.extend(c.0.to_bytes(&bo)?);
};
payload.extend(self.id.to_bytes(&bo));
self.header.set_payload_len(payload.len())?;
result.extend(self.header.to_bytes());
result.extend(payload);
Ok(result)
}
pub fn from_bytes(b: &[u8]) -> Result<Self, Error> {
let header = Header::from_bytes(b)?;
let bo = header.byte_order();
let mut b = b.get(header.byte_size()..).ok_or(ErrorKind::InvalidData)?;
let context = context_from_bytes(&header, b)?;
if let Some(c) = &context {
b = b.get(c.byte_size()..).ok_or(ErrorKind::InvalidData)?;
}
let id = ID::from_bytes(b, &bo)?;
Ok(Self {
header,
context,
id,
})
}
}
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub struct Response {
pub header: Header,
pub sys_uptime: Duration, pub res_error: ResError,
pub res_index: u16,
pub vb: Option<VarBindList>,
}
impl Default for Response {
fn default() -> Self {
Self {
header: Header::new(Type::Response),
sys_uptime: Duration::new(0, 0),
res_error: ResError::NoAgentXError,
res_index: 0,
vb: None,
}
}
}
impl Response {
pub fn new() -> Self {
Self::default()
}
pub fn from_header(header: &Header) -> Self {
let mut response = Self::new();
response.header.session_id = header.session_id;
response.header.transaction_id = header.transaction_id;
response.header.packet_id = header.packet_id;
response
}
pub fn to_bytes(&mut self) -> Result<Vec<u8>, Error> {
let mut result = Vec::new();
let mut payload = Vec::new();
let bo = self.header.byte_order();
let sys_uptime =
u32::try_from(self.sys_uptime.as_millis() / 10).map_err(|_| ErrorKind::InvalidData)?;
let sys_uptime = u32_to_bytes(sys_uptime, &bo);
payload.extend(&sys_uptime);
payload.extend(&self.res_error.to_bytes(&bo));
payload.extend(&u16_to_bytes(self.res_index, &bo));
if let Some(vb) = &self.vb {
payload.extend(vb.to_bytes(&bo)?);
}
self.header.set_payload_len(payload.len())?;
result.extend(self.header.to_bytes());
result.extend(payload);
Ok(result)
}
pub fn from_bytes(b: &[u8]) -> Result<Self, Error> {
let header = Header::from_bytes(b)?;
let bo = header.byte_order();
let mut b = b.get(header.byte_size()..).ok_or(ErrorKind::InvalidData)?;
let sys_uptime = bytes_to_u32(b, &bo)?;
let sys_uptime = Duration::from_millis((sys_uptime * 10) as u64);
b = b.get(4..).ok_or(ErrorKind::InvalidData)?;
let res_error = ResError::from_bytes(b, &bo)?;
b = b
.get(res_error.byte_size()..)
.ok_or(ErrorKind::InvalidData)?;
let res_index = bytes_to_u16(b, &bo)?;
let vb = match b.get(2..) {
None => None,
Some(b) => Some(VarBindList::from_bytes(b, &bo)?),
};
Ok(Self {
header,
sys_uptime,
res_error,
res_index,
vb,
})
}
}
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub enum Type {
Open,
Close,
Register,
Unregister,
Get,
GetNext,
GetBulk,
TestSet,
CommitSet,
UndoSet,
CleanupSet,
Notify,
Ping,
IndexAllocate,
IndexDeallocate,
AddAgentCaps,
RemoveAgentCaps,
Response,
}
impl Type {
pub fn to_byte(&self) -> u8 {
match self {
Self::Open => 1,
Self::Close => 2,
Self::Register => 3,
Self::Unregister => 4,
Self::Get => 5,
Self::GetNext => 6,
Self::GetBulk => 7,
Self::TestSet => 8,
Self::CommitSet => 9,
Self::UndoSet => 10,
Self::CleanupSet => 11,
Self::Notify => 12,
Self::Ping => 13,
Self::IndexAllocate => 14,
Self::IndexDeallocate => 15,
Self::AddAgentCaps => 16,
Self::RemoveAgentCaps => 17,
Self::Response => 18,
}
}
pub fn from_byte(b: u8) -> Result<Self, Error> {
let ty = match b {
1 => Self::Open,
2 => Self::Close,
3 => Self::Register,
4 => Self::Unregister,
5 => Self::Get,
6 => Self::GetNext,
7 => Self::GetBulk,
8 => Self::TestSet,
9 => Self::CommitSet,
10 => Self::UndoSet,
11 => Self::CleanupSet,
12 => Self::Notify,
13 => Self::Ping,
14 => Self::IndexAllocate,
15 => Self::IndexDeallocate,
16 => Self::AddAgentCaps,
17 => Self::RemoveAgentCaps,
18 => Self::Response,
_ => return Err(Error::from(ErrorKind::InvalidData)),
};
Ok(ty)
}
}
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub enum CloseReason {
Other,
ParseError,
ProtocolError,
Timeouts,
Shutdown,
ByManager,
}
impl CloseReason {
pub fn to_byte(&self) -> u8 {
match self {
Self::Other => 1,
Self::ParseError => 2,
Self::ProtocolError => 3,
Self::Timeouts => 4,
Self::Shutdown => 5,
Self::ByManager => 6,
}
}
pub fn from_byte(b: u8) -> Result<Self, Error> {
let ty = match b {
1 => Self::Other,
2 => Self::ParseError,
3 => Self::ProtocolError,
4 => Self::Timeouts,
5 => Self::Shutdown,
6 => Self::ByManager,
_ => return Err(Error::from(ErrorKind::InvalidData)),
};
Ok(ty)
}
}
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub enum ResError {
NoAgentXError,
OpenFailed,
NotOpen,
IndexWrongType,
IndexAlreadyAllocated,
IndexNoneAvailable,
IndexNotAllocated,
UnsupportedContext,
DuplicateRegistration,
UnknownRegistration,
UnknownAgentCaps,
ParseError,
RequestDenied,
ProcessingError,
}
impl ResError {
pub fn to_bytes(&self, bo: &ByteOrder) -> [u8; 2] {
let val = match self {
Self::NoAgentXError => 0,
Self::OpenFailed => 256,
Self::NotOpen => 257,
Self::IndexWrongType => 258,
Self::IndexAlreadyAllocated => 259,
Self::IndexNoneAvailable => 260,
Self::IndexNotAllocated => 261,
Self::UnsupportedContext => 262,
Self::DuplicateRegistration => 263,
Self::UnknownRegistration => 264,
Self::UnknownAgentCaps => 265,
Self::ParseError => 266,
Self::RequestDenied => 267,
Self::ProcessingError => 268,
};
u16_to_bytes(val, bo)
}
fn byte_size(&self) -> usize {
2
}
pub fn from_bytes(b: &[u8], bo: &ByteOrder) -> Result<Self, Error> {
let re = match bytes_to_u16(b, bo)? {
0 => Self::NoAgentXError,
256 => Self::OpenFailed,
257 => Self::NotOpen,
258 => Self::IndexWrongType,
259 => Self::IndexAlreadyAllocated,
260 => Self::IndexNoneAvailable,
261 => Self::IndexNotAllocated,
262 => Self::UnsupportedContext,
263 => Self::DuplicateRegistration,
264 => Self::UnknownRegistration,
265 => Self::UnknownAgentCaps,
266 => Self::ParseError,
267 => Self::RequestDenied,
268 => Self::ProcessingError,
_ => return Err(Error::from(ErrorKind::InvalidData)),
};
Ok(re)
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::str::FromStr;
#[test]
fn header_to_bytes_len() {
let header = Header::new(Type::Response);
assert_eq!(header.to_bytes().len(), 20);
}
#[test]
fn open_to_bytes() {
let mut open = Open::new(ID::from_str("1.2.3").unwrap(), "rck");
open.header.session_id = 1;
open.header.transaction_id = 2;
open.header.packet_id = 3;
let expected = vec![
1, 1, 0, 0,
1, 0, 0, 0,
2, 0, 0, 0,
3, 0, 0, 0,
28, 0, 0, 0,
0, 0, 0, 0,
3, 0, 0, 0,
1, 0, 0, 0,
2, 0, 0, 0,
3, 0, 0, 0,
3, 0, 0, 0,
0x72, 0x63, 0x6B, 0,
];
assert_eq!(expected, open.to_bytes().unwrap());
}
#[test]
fn open_serde() {
let mut expected = Open::new(ID::from_str("1.2.3.4").unwrap(), "rck");
expected.header.session_id = 1;
expected.header.transaction_id = 2342;
expected.header.packet_id = 3;
for bo in vec![0, NETWORK_BYTE_ORDER] {
if bo > 0 {
expected.header.flags |= 1 << bo;
}
let bytes = expected.to_bytes().unwrap();
let got = Open::from_bytes(bytes.as_slice()).unwrap();
assert_eq!(got.header.transaction_id, 2342);
assert_eq!(got, expected);
}
}
#[test]
fn close_serde() {
for flags in vec![0, 1 << NETWORK_BYTE_ORDER] {
let mut expected = Close::new(CloseReason::ParseError);
expected.header.flags = flags;
let bytes = expected.to_bytes().unwrap();
let got = Close::from_bytes(bytes.as_slice()).unwrap();
assert_eq!(got, expected);
}
}
#[test]
fn register_serde() {
for flags in vec![0, 1 << NETWORK_BYTE_ORDER] {
let mut expected = Register::new(ID::from_str("1.2.3").unwrap());
expected.header.flags = flags;
let bytes = expected.to_bytes().unwrap();
let got = Register::from_bytes(bytes.as_slice()).unwrap();
assert_eq!(got.context, None);
assert_eq!(got.upper_bound, None);
assert_eq!(got, expected);
}
let mut expected = Register::new(ID::from_str("1.2.3").unwrap());
expected.context = Some(Context(OctetString("rck".to_string())));
expected.header.flags = 1 << NON_DEFAULT_CONTEXT;
let bytes = expected.to_bytes().unwrap();
let got = Register::from_bytes(bytes.as_slice()).unwrap();
assert!(got.context.is_some());
assert_eq!(got, expected);
let mut expected = Register::new(ID::from_str("1.2.3").unwrap());
expected.range_subid = 2;
expected.upper_bound = Some(42);
let bytes = expected.to_bytes().unwrap();
let got = Register::from_bytes(bytes.as_slice()).unwrap();
assert_eq!(got.upper_bound, Some(42));
assert_eq!(got, expected);
}
#[test]
fn unregister_serde() {
for flags in vec![0, 1 << NETWORK_BYTE_ORDER] {
let mut expected = Unregister::new(ID::from_str("1.2.3").unwrap(), 23);
expected.header.flags = flags;
let bytes = expected.to_bytes().unwrap();
let got = Unregister::from_bytes(bytes.as_slice()).unwrap();
assert_eq!(got.context, None);
assert_eq!(got.upper_bound, None);
assert_eq!(got, expected);
}
}
}