use std::convert::TryFrom;
use std::fmt;
use std::io;
use std::num::{NonZeroU8, NonZeroUsize};
use derive_new::new as New;
use getset::Getters;
use crate::size::Size;
use crate::uuid::Uuid16;
use crate::{Handle, Uuid};
use pack::{Error as PackError, Pack, Result as PackResult, Unpack};
#[macro_use]
pub(crate) mod pack;
mod impls;
#[derive(Debug, PartialEq, Eq)]
pub enum ErrorCode {
InvalidHandle,
ReadNotPermitted,
WriteNotPermitted,
InvalidPDU,
InsufficientAuthentication,
RequestNotSupported,
InvalidOffset,
InsufficientAuthorization,
PrepareQueueFull,
AttributeNotFound,
AttributeNotLong,
InsufficientEncryptionKeySize,
InvalidAttributeValueLength,
UnlikelyError,
InsufficientEncryption,
UnsupportedGroupType,
InsufficientResources,
DatabaseOutOfSync,
ValueNotAllowed,
ApplicationError(u8),
CommonProfileAndServiceErrorCodes(u8),
ReservedForFutureUse(u8),
}
impl Pack for ErrorCode {
fn pack<W>(self, write: &mut W) -> PackResult<()>
where
W: io::Write,
{
let v = match self {
Self::InvalidHandle => 0x01,
Self::ReadNotPermitted => 0x02,
Self::WriteNotPermitted => 0x03,
Self::InvalidPDU => 0x04,
Self::InsufficientAuthentication => 0x05,
Self::RequestNotSupported => 0x06,
Self::InvalidOffset => 0x07,
Self::InsufficientAuthorization => 0x08,
Self::PrepareQueueFull => 0x09,
Self::AttributeNotFound => 0x0A,
Self::AttributeNotLong => 0x0B,
Self::InsufficientEncryptionKeySize => 0x0C,
Self::InvalidAttributeValueLength => 0x0D,
Self::UnlikelyError => 0x0E,
Self::InsufficientEncryption => 0x0F,
Self::UnsupportedGroupType => 0x10,
Self::InsufficientResources => 0x11,
Self::DatabaseOutOfSync => 0x12,
Self::ValueNotAllowed => 0x13,
Self::ApplicationError(v)
| Self::CommonProfileAndServiceErrorCodes(v)
| Self::ReservedForFutureUse(v) => v,
};
u8::pack(v, write)
}
}
impl Unpack for ErrorCode {
fn unpack<R>(read: &mut R) -> PackResult<Self>
where
R: io::Read,
{
Ok(match u8::unpack(read)? {
0x01 => Self::InvalidHandle,
0x02 => Self::ReadNotPermitted,
0x03 => Self::WriteNotPermitted,
0x04 => Self::InvalidPDU,
0x05 => Self::InsufficientAuthentication,
0x06 => Self::RequestNotSupported,
0x07 => Self::InvalidOffset,
0x08 => Self::InsufficientAuthorization,
0x09 => Self::PrepareQueueFull,
0x0A => Self::AttributeNotFound,
0x0B => Self::AttributeNotLong,
0x0C => Self::InsufficientEncryptionKeySize,
0x0D => Self::InvalidAttributeValueLength,
0x0E => Self::UnlikelyError,
0x0F => Self::InsufficientEncryption,
0x10 => Self::UnsupportedGroupType,
0x11 => Self::InsufficientResources,
0x12 => Self::DatabaseOutOfSync,
0x13 => Self::ValueNotAllowed,
v if (0x80..=0x9F).contains(&v) => Self::ApplicationError(v),
v if (0xE0..=0xFF).contains(&v) => Self::CommonProfileAndServiceErrorCodes(v),
v => Self::ReservedForFutureUse(v),
})
}
}
#[derive(Debug)]
struct HandlesInformationList(Vec<(Handle, Handle)>);
impl Pack for HandlesInformationList {
fn pack<W>(self, write: &mut W) -> PackResult<()>
where
W: io::Write,
{
pack::RemainingVec(self.0).pack(write)
}
}
impl Unpack for HandlesInformationList {
fn unpack<R>(read: &mut R) -> PackResult<Self>
where
R: io::Read,
{
let v = pack::RemainingVec::<(Handle, Handle)>::unpack(read)?;
Ok(Self(v.0))
}
}
#[derive(Debug)]
struct SetOfHandles(Vec<Handle>);
impl<'a> IntoIterator for &'a SetOfHandles {
type Item = &'a Handle;
type IntoIter = std::slice::Iter<'a, Handle>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter()
}
}
impl Pack for SetOfHandles {
fn pack<W>(self, write: &mut W) -> PackResult<()>
where
W: io::Write,
{
pack::RemainingVec(self.0).pack(write)
}
}
impl Unpack for SetOfHandles {
fn unpack<R>(read: &mut R) -> PackResult<Self>
where
R: io::Read,
{
let v = pack::RemainingVec::<Handle>::unpack(read)?;
Ok(Self(v.0))
}
}
trait AttributeData: Pack + Unpack {
fn format(&self) -> NonZeroU8;
fn len(val: NonZeroU8) -> PackResult<NonZeroUsize> {
Ok(val.into())
}
}
impl AttributeData for (Handle, Uuid) {
fn format(&self) -> NonZeroU8 {
match &self.1 {
Uuid::Uuid16(_) => NonZeroU8::new(0x01).unwrap(),
Uuid::Uuid128(_) => NonZeroU8::new(0x02).unwrap(),
}
}
fn len(val: NonZeroU8) -> PackResult<NonZeroUsize> {
Ok(match val.get() {
0x01 => NonZeroUsize::new(2 + 2).unwrap(),
0x02 => NonZeroUsize::new(2 + 16).unwrap(),
unknown => return Err(PackError::Unexpected(format!("format {}", unknown))),
})
}
}
impl AttributeData for (Handle, Box<[u8]>) {
fn format(&self) -> NonZeroU8 {
NonZeroU8::new(2 + self.1.len() as u8).unwrap()
}
}
impl AttributeData for (Handle, Handle, Box<[u8]>) {
fn format(&self) -> NonZeroU8 {
NonZeroU8::new(2 + 2 + self.2.len() as u8).unwrap()
}
}
#[derive(Debug)]
struct AttributeDataList<T>(Vec<T>);
impl<A> Pack for AttributeDataList<A>
where
A: AttributeData,
{
fn pack<W>(self, write: &mut W) -> PackResult<()>
where
W: io::Write,
{
if self.0.is_empty() {
return 0u8.pack(write);
}
let format = self.0[0].format();
let len = A::len(format)?.get();
let mut buf = vec![0; len];
format.get().pack(write)?;
for data in self.0 {
let mut w = &mut buf[..];
data.pack(&mut w)?;
if !w.is_empty() {
return Err(PackError::Unexpected("length".into()));
}
write.write_all(&buf)?;
}
Ok(())
}
}
impl<A> Unpack for AttributeDataList<A>
where
A: AttributeData,
{
fn unpack<R>(read: &mut R) -> PackResult<Self>
where
R: io::Read,
{
let format = u8::unpack(read)?;
let format = if let Some(format) = NonZeroU8::new(format) {
format
} else {
return Ok(Self(vec![]));
};
let len = A::len(format)?.get();
let mut buf = vec![0; len];
let mut items = vec![];
loop {
let mut rest = buf.len();
while rest > 0 {
let n = read.read(&mut buf)?;
if n > 0 {
rest -= n;
} else {
break;
}
}
if rest == buf.len() {
return Ok(Self(items));
}
let item = A::unpack(&mut &buf[..])?;
items.push(item);
}
}
}
macro_rules! packet {
(
$(
$(#[$attrs:meta])*
$vis:vis struct $name:ident : $op:literal {
$(
$(#[$fattrs:meta])*
$fvis:vis $fname:ident : $fty:ty,
)*
}
)*
) => {
$(
packable_struct! {
$(#[$attrs])*
$vis struct $name {
$(
$(#[$fattrs])*
$fvis $fname : $fty,
)*
}
}
impl Packet for $name {
const OPCODE: OpCode = OpCode::$name;
}
)*
packable_enum! {
#[derive(Debug, PartialEq, Eq, Hash)]
pub enum OpCode: u8 {
$($name = $op,)*
}
}
pub trait Packet: fmt::Debug {
const OPCODE: OpCode;
fn opcode() -> OpCode {
Self::OPCODE
}
}
}
}
packet! {
#[derive(Debug, New, Getters)]
pub struct ErrorResponse: 0x01 {
request_opcode_in_error: OpCode,
attribute_handle_in_error: Handle,
error_code: ErrorCode,
}
#[derive(Debug, New, Getters)]
#[get = "pub"]
pub struct ExchangeMtuRequest: 0x02 {
client_rx_mtu: u16,
}
#[derive(Debug, New, Getters)]
#[get = "pub"]
pub struct ExchangeMtuResponse: 0x03 {
server_rx_mtu: u16,
}
#[derive(Debug, New, Getters)]
#[get = "pub"]
pub struct FindInformationRequest: 0x04 {
starting_handle: Handle,
ending_handle: Handle,
}
#[derive(Debug)]
pub struct FindInformationResponse: 0x05 {
values: AttributeDataList<(Handle, Uuid)>, }
#[derive(Debug, New, Getters)]
#[get = "pub"]
pub struct FindByTypeValueRequest: 0x06 {
starting_handle: Handle,
ending_handle: Handle,
attribute_type: Uuid16,
attribute_value: Box<[u8]>,
}
#[derive(Debug)]
pub struct FindByTypeValueResponse: 0x07 {
values: HandlesInformationList,
}
#[derive(Debug, New, Getters)]
#[get = "pub"]
pub struct ReadByTypeRequest: 0x08 {
starting_handle: Handle,
ending_handle: Handle,
attribute_type: Uuid,
}
#[derive(Debug)]
pub struct ReadByTypeResponse: 0x09 {
values: AttributeDataList<(Handle, Box<[u8]>)>,
}
#[derive(Debug, New, Getters)]
#[get = "pub"]
pub struct ReadRequest: 0x0A {
attribute_handle: Handle,
}
#[derive(Debug, New, Getters)]
#[get = "pub"]
pub struct ReadResponse: 0x0B {
attribute_value: Box<[u8]>,
}
#[derive(Debug, New, Getters)]
#[get = "pub"]
pub struct ReadBlobRequest: 0x0C {
attribute_handle: Handle,
attribute_offset: u16,
}
#[derive(Debug, New, Getters)]
#[get = "pub"]
pub struct ReadBlobResponse: 0x0D {
attribute_value: Box<[u8]>,
}
#[derive(Debug)]
pub struct ReadMultipleRequest: 0x0E {
set_of_handles: SetOfHandles,
}
#[derive(Debug, New)]
pub struct ReadMultipleResponse: 0x0F {
set_of_values: Box<[u8]>, }
#[derive(Debug, New, Getters)]
#[get = "pub"]
pub struct ReadByGroupTypeRequest: 0x10 {
starting_handle: Handle,
ending_handle: Handle,
attribute_group_type: Uuid,
}
#[derive(Debug)]
pub struct ReadByGroupTypeResponse: 0x11 {
values: AttributeDataList<(Handle, Handle, Box<[u8]>)>,
}
#[derive(Debug, New, Getters)]
#[get = "pub"]
pub struct WriteRequest: 0x12 {
attribute_handle: Handle,
attribute_value: Box<[u8]>,
}
#[derive(Debug, New, Default)]
pub struct WriteResponse: 0x13 {
}
#[derive(Debug, New, Getters)]
#[get = "pub"]
pub struct WriteCommand: 0x52 {
attribute_handle: Handle,
attribute_value: Box<[u8]>,
}
#[derive(Debug, New, Getters)]
#[get = "pub"]
pub struct SignedWriteCommand: 0xD2 {
attribute_handle: Handle,
attribute_value: Box<[u8]>,
authentication_signature: Box<[u8]>, }
#[derive(Debug, New, Getters)]
#[get = "pub"]
pub struct PrepareWriteRequest: 0x16 {
attribute_handle: Handle,
value_offset: u16,
part_attribute_value: Box<[u8]>,
}
#[derive(Debug, New, Getters)]
#[get = "pub"]
pub struct PrepareWriteResponse: 0x17 {
attribute_handle: Handle,
value_offset: u16,
part_attribute_value: Box<[u8]>,
}
#[derive(Debug, New, Getters)]
#[get = "pub"]
pub struct ExecuteWriteRequest: 0x18 {
flags: bool,
}
#[derive(Debug, New, Default)]
pub struct ExecuteWriteResponse: 0x19 {
}
#[derive(Debug, New, Getters)]
#[get = "pub"]
pub struct HandleValueNotification: 0x1B {
attribute_handle: Handle,
attribute_value: Box<[u8]>,
}
#[derive(Debug, New, Getters)]
#[get = "pub"]
pub struct HandleValueIndication: 0x1D {
attribute_handle: Handle,
attribute_value: Box<[u8]>,
}
#[derive(Debug, New, Default)]
pub struct HandleValueConfirmation: 0x1E {
}
}
macro_rules! device_recv {
(
$( $ident:ident, )*
) => {
#[derive(Debug)]
pub enum DeviceRecv {
$( $ident($ident), )*
}
trait AssertUnpack: Packet + Unpack + Sized {}
$(
impl AssertUnpack for $ident {}
impl From<$ident> for DeviceRecv {
fn from(v: $ident) -> Self {
Self::$ident(v)
}
}
impl TryFrom<DeviceRecv> for $ident {
type Error = DeviceRecv;
fn try_from(v: DeviceRecv) -> std::result::Result<Self, Self::Error> {
match v {
DeviceRecv::$ident(v) => Ok(v),
v => Err(v),
}
}
}
)*
impl Unpack for DeviceRecv {
fn unpack<R>(read: &mut R) -> PackResult<Self> where R: io::Read {
Ok(match OpCode::unpack(read)? {
$( OpCode::$ident => $ident::unpack(read)?.into(), )*
unknown => return Err(PackError::Unexpected(format!("{:?}", unknown))),
})
}
}
}
}
macro_rules! device_send {
( $( $ident:ident, )* ) => {
$(
impl DeviceSend for $ident { }
)*
}
}
device_recv![
ExchangeMtuRequest,
FindInformationRequest,
FindByTypeValueRequest,
ReadByTypeRequest,
ReadRequest,
ReadBlobRequest,
ReadMultipleRequest,
ReadByGroupTypeRequest,
WriteRequest,
PrepareWriteRequest,
ExecuteWriteRequest,
WriteCommand,
SignedWriteCommand,
HandleValueConfirmation,
];
device_send![
ErrorResponse,
ExchangeMtuResponse,
FindInformationResponse,
FindByTypeValueResponse,
ReadByTypeResponse,
ReadResponse,
ReadBlobResponse,
ReadMultipleResponse,
ReadByGroupTypeResponse,
WriteResponse,
PrepareWriteResponse,
ExecuteWriteResponse,
HandleValueNotification,
HandleValueIndication,
];
pub trait DeviceSend: Packet + Pack + Sized {
fn pack_with_code<W>(self, write: &mut W) -> PackResult<()>
where
W: io::Write,
{
Self::OPCODE.pack(write)?;
self.pack(write)?;
Ok(())
}
}
pub trait Request: Packet + TryFrom<DeviceRecv> {
type Response: Response;
}
pub trait Response: Packet + DeviceSend {
fn truncate(&mut self, mtu: usize);
}
pub trait Command: Packet + TryFrom<DeviceRecv> {}
pub trait Notification: Packet + DeviceSend {}
pub trait Indication: Packet + DeviceSend {
type Confirmation: Confirmation;
}
pub trait Confirmation: Packet + TryFrom<DeviceRecv> {}
impl Response for ErrorResponse {
fn truncate(&mut self, _: usize) {}
}
impl Request for ExchangeMtuRequest {
type Response = ExchangeMtuResponse;
}
impl Response for ExchangeMtuResponse {
fn truncate(&mut self, _: usize) {}
}
impl Request for FindInformationRequest {
type Response = FindInformationResponse;
}
impl Response for FindInformationResponse {
fn truncate(&mut self, mtu: usize) {
let mut remaining = mtu - 2;
let mut len = 0;
for item in &self.values.0 {
let item_len = item.size();
if item_len > remaining {
break;
}
remaining -= item_len;
len += 1;
}
self.values.0.truncate(len);
}
}
impl Request for FindByTypeValueRequest {
type Response = FindByTypeValueResponse;
}
impl Response for FindByTypeValueResponse {
fn truncate(&mut self, mtu: usize) {
let mut remaining = mtu - 1;
let mut len = 0;
for item in &self.values.0 {
let item_len = item.size();
if item_len > remaining {
break;
}
remaining -= item_len;
len += 1;
}
self.values.0.truncate(len);
}
}
impl Request for ReadByTypeRequest {
type Response = ReadByTypeResponse;
}
impl Response for ReadByTypeResponse {
fn truncate(&mut self, mtu: usize) {
let mut remaining = mtu - 2;
let mut len = 0;
for item in &self.values.0 {
let item_len = item.size();
if item_len > remaining {
break;
}
remaining -= item_len;
len += 1;
}
self.values.0.truncate(len);
}
}
impl Request for ReadRequest {
type Response = ReadResponse;
}
impl Response for ReadResponse {
fn truncate(&mut self, mtu: usize) {
if self.attribute_value.len() > mtu - 1 {
self.attribute_value = (&self.attribute_value[..mtu - 1]).into();
}
}
}
impl Request for ReadBlobRequest {
type Response = ReadBlobResponse;
}
impl Response for ReadBlobResponse {
fn truncate(&mut self, mtu: usize) {
if self.attribute_value.len() > mtu - 1 {
self.attribute_value = (&self.attribute_value[..mtu - 1]).into();
}
}
}
impl Request for ReadMultipleRequest {
type Response = ReadMultipleResponse;
}
impl Response for ReadMultipleResponse {
fn truncate(&mut self, mtu: usize) {
if self.set_of_values.len() > mtu - 1 {
self.set_of_values = (&self.set_of_values[..mtu - 1]).into();
}
}
}
impl Request for ReadByGroupTypeRequest {
type Response = ReadByGroupTypeResponse;
}
impl Response for ReadByGroupTypeResponse {
fn truncate(&mut self, mtu: usize) {
let mut remaining = mtu - 2;
let mut len = 0;
for item in &self.values.0 {
let item_len = item.size();
if item_len > remaining {
break;
}
remaining -= item_len;
len += 1;
}
self.values.0.truncate(len);
}
}
impl Request for WriteRequest {
type Response = WriteResponse;
}
impl Response for WriteResponse {
fn truncate(&mut self, _: usize) {}
}
impl Command for WriteCommand {}
impl Request for PrepareWriteRequest {
type Response = PrepareWriteResponse;
}
impl Response for PrepareWriteResponse {
fn truncate(&mut self, mtu: usize) {
if self.part_attribute_value.len() > mtu - 1 {
self.part_attribute_value = (&self.part_attribute_value[..mtu - 1]).into();
}
}
}
impl Request for ExecuteWriteRequest {
type Response = ExecuteWriteResponse;
}
impl Response for ExecuteWriteResponse {
fn truncate(&mut self, _: usize) {}
}
impl Notification for HandleValueNotification {}
impl Indication for HandleValueIndication {
type Confirmation = HandleValueConfirmation;
}
impl Confirmation for HandleValueConfirmation {}
impl Command for SignedWriteCommand {}
#[derive(Debug, New)]
pub struct HandleValueNotificationBorrow<'a>(Handle, &'a [u8]);
impl<'a> Packet for HandleValueNotificationBorrow<'a> {
const OPCODE: OpCode = HandleValueNotification::OPCODE;
}
impl<'a> Pack for HandleValueNotificationBorrow<'a> {
fn pack<W>(self, write: &mut W) -> PackResult<()>
where
W: io::Write,
{
self.0.pack(write)?;
write.write_all(self.1)?;
Ok(())
}
}
impl<'a> DeviceSend for HandleValueNotificationBorrow<'a> {}
impl<'a> Notification for HandleValueNotificationBorrow<'a> {}
#[derive(Debug, New)]
pub struct HandleValueIndicationBorrow<'a>(Handle, &'a [u8]);
impl<'a> Packet for HandleValueIndicationBorrow<'a> {
const OPCODE: OpCode = HandleValueIndication::OPCODE;
}
impl<'a> Pack for HandleValueIndicationBorrow<'a> {
fn pack<W>(self, write: &mut W) -> PackResult<()>
where
W: io::Write,
{
self.0.pack(write)?;
write.write_all(self.1)?;
Ok(())
}
}
impl<'a> DeviceSend for HandleValueIndicationBorrow<'a> {}
impl<'a> Indication for HandleValueNotificationBorrow<'a> {
type Confirmation = HandleValueConfirmation;
}