diff --git a/Cargo.toml b/Cargo.toml index 7b2660c..268671d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,4 +1,4 @@ [workspace] -members = ["matter", "matter_macro_derive", "boxslab", "tools/tlv_tool"] +members = ["matter", "matter_macro_derive", "tools/tlv_tool"] exclude = ["examples/*"] diff --git a/boxslab/Cargo.toml b/boxslab/Cargo.toml deleted file mode 100644 index fa4f430..0000000 --- a/boxslab/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "boxslab" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -bitmaps={version="3.2.0", features=[]} diff --git a/boxslab/src/lib.rs b/boxslab/src/lib.rs deleted file mode 100644 index f25cbd4..0000000 --- a/boxslab/src/lib.rs +++ /dev/null @@ -1,237 +0,0 @@ -/* - * - * Copyright (c) 2020-2022 Project CHIP Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -use std::{ - mem::MaybeUninit, - ops::{Deref, DerefMut}, - sync::Mutex, -}; - -// TODO: why is max bitmap size 64 a correct max size? Could we match -// boxslabs instead or store used/not used inside the box slabs themselves? -const MAX_BITMAP_SIZE: usize = 64; -pub struct Bitmap { - inner: bitmaps::Bitmap, - max_size: usize, -} - -impl Bitmap { - pub fn new(max_size: usize) -> Self { - assert!(max_size <= MAX_BITMAP_SIZE); - Bitmap { - inner: bitmaps::Bitmap::new(), - max_size, - } - } - - pub fn set(&mut self, index: usize) -> bool { - assert!(index < self.max_size); - self.inner.set(index, true) - } - - pub fn reset(&mut self, index: usize) -> bool { - assert!(index < self.max_size); - self.inner.set(index, false) - } - - pub fn first_false_index(&self) -> Option { - match self.inner.first_false_index() { - Some(idx) if idx < self.max_size => Some(idx), - _ => None, - } - } - - pub fn is_empty(&self) -> bool { - self.inner.is_empty() - } - - pub fn is_full(&self) -> bool { - self.first_false_index().is_none() - } -} - -#[macro_export] -macro_rules! box_slab { - ($name:ident,$t:ty,$v:expr) => { - use std::mem::MaybeUninit; - use std::sync::Once; - use $crate::{BoxSlab, Slab, SlabPool}; - - pub struct $name; - - impl SlabPool for $name { - type SlabType = $t; - fn get_slab() -> &'static Slab { - const MAYBE_INIT: MaybeUninit<$t> = MaybeUninit::uninit(); - static mut SLAB_POOL: [MaybeUninit<$t>; $v] = [MAYBE_INIT; $v]; - static mut SLAB_SPACE: Option> = None; - static mut INIT: Once = Once::new(); - unsafe { - INIT.call_once(|| { - SLAB_SPACE = Some(Slab::<$name>::init(&mut SLAB_POOL, $v)); - }); - SLAB_SPACE.as_ref().unwrap() - } - } - } - }; -} - -pub trait SlabPool { - type SlabType: 'static; - fn get_slab() -> &'static Slab - where - Self: Sized; -} - -pub struct Inner { - pool: &'static mut [MaybeUninit], - map: Bitmap, -} - -// TODO: Instead of a mutex, we should replace this with a CAS loop -pub struct Slab(Mutex>); - -impl Slab { - pub fn init(pool: &'static mut [MaybeUninit], size: usize) -> Self { - Self(Mutex::new(Inner { - pool, - map: Bitmap::new(size), - })) - } - - pub fn try_new(new_object: T::SlabType) -> Option> { - let slab = T::get_slab(); - let mut inner = slab.0.lock().unwrap(); - if let Some(index) = inner.map.first_false_index() { - inner.map.set(index); - inner.pool[index].write(new_object); - let cell_ptr = unsafe { &mut *inner.pool[index].as_mut_ptr() }; - Some(BoxSlab { - data: cell_ptr, - index, - }) - } else { - None - } - } - - pub fn free(&self, index: usize) { - let mut inner = self.0.lock().unwrap(); - inner.map.reset(index); - let old_value = std::mem::replace(&mut inner.pool[index], MaybeUninit::uninit()); - let _old_value = unsafe { old_value.assume_init() }; - // This will drop the old_value - } -} - -pub struct BoxSlab { - // Because the data is a reference within the MaybeUninit, we don't have a mechanism - // to go out to the MaybeUninit from this reference. Hence this index - index: usize, - // TODO: We should figure out a way to get rid of the index too - data: &'static mut T::SlabType, -} - -impl Drop for BoxSlab { - fn drop(&mut self) { - T::get_slab().free(self.index); - } -} - -impl Deref for BoxSlab { - type Target = T::SlabType; - fn deref(&self) -> &Self::Target { - self.data - } -} - -impl DerefMut for BoxSlab { - fn deref_mut(&mut self) -> &mut Self::Target { - self.data - } -} - -#[cfg(test)] -mod tests { - use std::{ops::Deref, sync::Arc}; - - pub struct Test { - val: Arc, - } - - box_slab!(TestSlab, Test, 3); - - #[test] - fn simple_alloc_free() { - { - let a = Slab::::try_new(Test { val: Arc::new(10) }).unwrap(); - assert_eq!(*a.val.deref(), 10); - let inner = TestSlab::get_slab().0.lock().unwrap(); - assert!(!inner.map.is_empty()); - } - // Validates that the 'Drop' got executed - let inner = TestSlab::get_slab().0.lock().unwrap(); - assert!(inner.map.is_empty()); - println!("Box Size {}", std::mem::size_of::>()); - println!("BoxSlab Size {}", std::mem::size_of::>()); - } - - #[test] - fn alloc_full_block() { - { - let a = Slab::::try_new(Test { val: Arc::new(10) }).unwrap(); - let b = Slab::::try_new(Test { val: Arc::new(11) }).unwrap(); - let c = Slab::::try_new(Test { val: Arc::new(12) }).unwrap(); - // Test that at overflow, we return None - assert!(Slab::::try_new(Test { val: Arc::new(13) }).is_none(),); - assert_eq!(*b.val.deref(), 11); - - { - let inner = TestSlab::get_slab().0.lock().unwrap(); - // Test that the bitmap is marked as full - assert!(inner.map.is_full()); - } - - // Purposefully drop, to test that new allocation is possible - std::mem::drop(b); - let d = Slab::::try_new(Test { val: Arc::new(21) }).unwrap(); - assert_eq!(*d.val.deref(), 21); - - // Ensure older allocations are still valid - assert_eq!(*a.val.deref(), 10); - assert_eq!(*c.val.deref(), 12); - } - - // Validates that the 'Drop' got executed - test that the bitmap is empty - let inner = TestSlab::get_slab().0.lock().unwrap(); - assert!(inner.map.is_empty()); - } - - #[test] - fn test_drop_logic() { - let root = Arc::new(10); - { - let _a = Slab::::try_new(Test { val: root.clone() }).unwrap(); - let _b = Slab::::try_new(Test { val: root.clone() }).unwrap(); - let _c = Slab::::try_new(Test { val: root.clone() }).unwrap(); - assert_eq!(Arc::strong_count(&root), 4); - } - // Test that Drop was correctly called on all the members of the pool - assert_eq!(Arc::strong_count(&root), 1); - } -} diff --git a/examples/onoff_light/src/main.rs b/examples/onoff_light/src/main.rs index 123c0da..1748b59 100644 --- a/examples/onoff_light/src/main.rs +++ b/examples/onoff_light/src/main.rs @@ -51,7 +51,7 @@ fn main() { //let mut mdns = matter::mdns::astro::AstroMdns::new().unwrap(); let mut mdns = matter::mdns::libmdns::LibMdns::new().unwrap(); - let matter = Matter::new_default(&dev_info, &mut mdns); + let matter = Matter::new_default(&dev_info, &mut mdns, matter::transport::udp::MATTER_PORT); let dev_att = dev_att::HardCodedDevAtt::new(); diff --git a/matter/Cargo.toml b/matter/Cargo.toml index cfc9964..9f5503b 100644 --- a/matter/Cargo.toml +++ b/matter/Cargo.toml @@ -25,7 +25,6 @@ crypto_esp_mbedtls = ["esp-idf-sys"] crypto_rustcrypto = ["sha2", "hmac", "pbkdf2", "hkdf", "aes", "ccm", "p256", "elliptic-curve", "crypto-bigint", "x509-cert"] [dependencies] -boxslab = { path = "../boxslab" } matter_macro_derive = { path = "../matter_macro_derive" } bitflags = "1.3" byteorder = "1.4.3" @@ -35,6 +34,7 @@ num-derive = "0.3.3" num-traits = "0.2.15" strum = { version = "0.24", features = ["derive"], default-features = false, no-default-feature = true } log = { version = "0.4.17", features = ["max_level_debug", "release_max_level_debug"] } +no-std-net = "0.6" subtle = "2.4.1" safemem = "0.3.3" colored = "2.0.0" # TODO: Requires STD diff --git a/matter/src/core.rs b/matter/src/core.rs index 41c5307..0939a4a 100644 --- a/matter/src/core.rs +++ b/matter/src/core.rs @@ -25,7 +25,6 @@ use crate::{ mdns::{Mdns, MdnsMgr}, pairing::{print_pairing_code_and_qr, DiscoveryCapabilities}, secure_channel::{pake::PaseMgr, spake2p::VerifierData}, - transport::udp::MATTER_PORT, utils::{ epoch::{Epoch, UtcCalendar}, rand::Rand, @@ -55,11 +54,11 @@ pub struct Matter<'a> { impl<'a> Matter<'a> { #[cfg(feature = "std")] - pub fn new_default(dev_det: &'a BasicInfoConfig, mdns: &'a mut dyn Mdns) -> Self { + pub fn new_default(dev_det: &'a BasicInfoConfig, mdns: &'a mut dyn Mdns, port: u16) -> Self { use crate::utils::epoch::{sys_epoch, sys_utc_calendar}; use crate::utils::rand::sys_rand; - Self::new(dev_det, mdns, sys_epoch, sys_rand, sys_utc_calendar) + Self::new(dev_det, mdns, sys_epoch, sys_rand, sys_utc_calendar, port) } /// Creates a new Matter object @@ -74,6 +73,7 @@ impl<'a> Matter<'a> { epoch: Epoch, rand: Rand, utc_calendar: UtcCalendar, + port: u16, ) -> Self { Self { fabric_mgr: RefCell::new(FabricMgr::new()), @@ -84,7 +84,7 @@ impl<'a> Matter<'a> { dev_det.vid, dev_det.pid, dev_det.device_name, - MATTER_PORT, + port, mdns, )), epoch, diff --git a/matter/src/error.rs b/matter/src/error.rs index e644a7a..d2053d1 100644 --- a/matter/src/error.rs +++ b/matter/src/error.rs @@ -17,8 +17,6 @@ use core::{array::TryFromSliceError, fmt, str::Utf8Error}; -use log::error; - #[derive(Debug, PartialEq, Clone, Copy)] pub enum Error { AttributeNotFound, @@ -122,7 +120,7 @@ impl From> for Error { #[cfg(feature = "crypto_openssl")] impl From for Error { fn from(e: openssl::error::ErrorStack) -> Self { - error!("Error in TLS: {}", e); + ::log::error!("Error in TLS: {}", e); Self::TLSStack } } @@ -130,7 +128,7 @@ impl From for Error { #[cfg(feature = "crypto_mbedtls")] impl From for Error { fn from(e: mbedtls::Error) -> Self { - error!("Error in TLS: {}", e); + ::log::error!("Error in TLS: {}", e); Self::TLSStack } } diff --git a/matter/src/lib.rs b/matter/src/lib.rs index 0d99cdb..1d7e5d4 100644 --- a/matter/src/lib.rs +++ b/matter/src/lib.rs @@ -85,7 +85,6 @@ pub mod mdns; pub mod pairing; pub mod persist; pub mod secure_channel; -pub mod sys; pub mod tlv; pub mod transport; pub mod utils; diff --git a/matter/src/sys/mod.rs b/matter/src/sys/mod.rs deleted file mode 100644 index a80b875..0000000 --- a/matter/src/sys/mod.rs +++ /dev/null @@ -1,20 +0,0 @@ -/* - * - * Copyright (c) 2020-2022 Project CHIP Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// The Packet Pool that is allocated from. POSIX systems can use -// higher values unlike embedded systems -pub const MAX_PACKET_POOL_SIZE: usize = 25; diff --git a/matter/src/transport/mod.rs b/matter/src/transport/mod.rs index 1a81c75..0b6453e 100644 --- a/matter/src/transport/mod.rs +++ b/matter/src/transport/mod.rs @@ -25,4 +25,5 @@ pub mod plain_hdr; pub mod proto_ctx; pub mod proto_hdr; pub mod session; +#[cfg(feature = "std")] pub mod udp; diff --git a/matter/src/transport/network.rs b/matter/src/transport/network.rs index 91645de..6cda9bc 100644 --- a/matter/src/transport/network.rs +++ b/matter/src/transport/network.rs @@ -16,6 +16,9 @@ */ use core::fmt::{Debug, Display}; +#[cfg(not(feature = "std"))] +use no_std_net::{IpAddr, Ipv4Addr, SocketAddr}; +#[cfg(feature = "std")] use std::net::{IpAddr, Ipv4Addr, SocketAddr}; #[derive(PartialEq, Copy, Clone)] diff --git a/matter/src/transport/packet.rs b/matter/src/transport/packet.rs index b2ca7aa..a86bf69 100644 --- a/matter/src/transport/packet.rs +++ b/matter/src/transport/packet.rs @@ -15,14 +15,10 @@ * limitations under the License. */ -use log::{error, trace}; -use std::sync::Mutex; - -use boxslab::box_slab; +use log::error; use crate::{ error::Error, - sys::MAX_PACKET_POOL_SIZE, utils::{parsebuf::ParseBuf, writebuf::WriteBuf}, }; @@ -34,54 +30,6 @@ use super::{ pub const MAX_RX_BUF_SIZE: usize = 1583; pub const MAX_TX_BUF_SIZE: usize = 1280 - 40/*IPV6 header size*/ - 8/*UDP header size*/; -type Buffer = [u8; MAX_RX_BUF_SIZE]; - -// TODO: I am not very happy with this construction, need to find another way to do this -pub struct BufferPool { - buffers: [Option; MAX_PACKET_POOL_SIZE], -} - -impl BufferPool { - const INIT: Option = None; - fn get() -> &'static Mutex { - static mut BUFFER_HOLDER: Option> = None; - static ONCE: Once = Once::new(); - unsafe { - ONCE.call_once(|| { - BUFFER_HOLDER = Some(Mutex::new(BufferPool { - buffers: [BufferPool::INIT; MAX_PACKET_POOL_SIZE], - })); - }); - BUFFER_HOLDER.as_ref().unwrap() - } - } - - pub fn alloc() -> Option<(usize, &'static mut Buffer)> { - trace!("Buffer Alloc called\n"); - - let mut pool = BufferPool::get().lock().unwrap(); - for i in 0..MAX_PACKET_POOL_SIZE { - if pool.buffers[i].is_none() { - pool.buffers[i] = Some([0; MAX_RX_BUF_SIZE]); - // Sigh! to by-pass the borrow-checker telling us we are stealing a mutable reference - // from under the lock - // In this case the lock only protects against the setting of Some/None, - // the objects then are independently accessed in a unique way - let buffer = unsafe { &mut *(pool.buffers[i].as_mut().unwrap() as *mut Buffer) }; - return Some((i, buffer)); - } - } - None - } - - pub fn free(index: usize) { - trace!("Buffer Free called\n"); - let mut pool = BufferPool::get().lock().unwrap(); - if pool.buffers[index].is_some() { - pool.buffers[index] = None; - } - } -} #[derive(PartialEq)] enum RxState { @@ -229,5 +177,3 @@ impl<'a> Packet<'a> { } } } - -box_slab!(PacketPool, Packet<'static>, MAX_PACKET_POOL_SIZE);