diff --git a/Cargo.toml b/Cargo.toml index 528f89a32..3693bfba9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,8 +16,13 @@ license = "0BSD" # ensure that the correct features are enabled. autoexamples = false +[dependencies.managed] +rev = "428ccc2def4ce0e14a669320ef0a676d3c79afac" +git = "https://github.com/cavivie/rust-managed.git" +default-features = false +features = ["map"] + [dependencies] -managed = { version = "0.8", default-features = false, features = ["map"] } byteorder = { version = "1.0", default-features = false } log = { version = "0.4.4", default-features = false, optional = true } libc = { version = "0.2.18", optional = true } diff --git a/src/iface/interface/ethernet.rs b/src/iface/interface/ethernet.rs index 4d29faa11..11796b73a 100644 --- a/src/iface/interface/ethernet.rs +++ b/src/iface/interface/ethernet.rs @@ -1,13 +1,16 @@ use super::*; impl InterfaceInner { - pub(super) fn process_ethernet<'frame>( + pub(super) fn process_ethernet<'frame, 'socket, S>( &mut self, - sockets: &mut SocketSet, + sockets: &mut S, meta: crate::phy::PacketMeta, frame: &'frame [u8], fragments: &'frame mut FragmentsBuffer, - ) -> Option> { + ) -> Option> + where + S: AnySocketSet<'socket>, + { let eth_frame = check!(EthernetFrame::new_checked(frame)); // Ignore any packets not directed to our hardware address or any of the multicast groups. diff --git a/src/iface/interface/ieee802154.rs b/src/iface/interface/ieee802154.rs index c053ec3dd..e71d15486 100644 --- a/src/iface/interface/ieee802154.rs +++ b/src/iface/interface/ieee802154.rs @@ -9,13 +9,16 @@ impl InterfaceInner { no } - pub(super) fn process_ieee802154<'output, 'payload: 'output>( + pub(super) fn process_ieee802154<'output, 'payload: 'output, 'socket, S>( &mut self, - sockets: &mut SocketSet, + sockets: &mut S, meta: PacketMeta, sixlowpan_payload: &'payload [u8], _fragments: &'output mut FragmentsBuffer, - ) -> Option> { + ) -> Option> + where + S: AnySocketSet<'socket>, + { let ieee802154_frame = check!(Ieee802154Frame::new_checked(sixlowpan_payload)); if ieee802154_frame.frame_type() != Ieee802154FrameType::Data { diff --git a/src/iface/interface/ipv4.rs b/src/iface/interface/ipv4.rs index 3a5a864ee..75079b4fc 100644 --- a/src/iface/interface/ipv4.rs +++ b/src/iface/interface/ipv4.rs @@ -87,13 +87,16 @@ impl InterfaceInner { }) } - pub(super) fn process_ipv4<'a>( + pub(super) fn process_ipv4<'a, 'socket, S>( &mut self, - sockets: &mut SocketSet, + sockets: &mut S, meta: PacketMeta, ipv4_packet: &Ipv4Packet<&'a [u8]>, frag: &'a mut FragmentsBuffer, - ) -> Option> { + ) -> Option> + where + S: AnySocketSet<'socket>, + { let ipv4_repr = check!(Ipv4Repr::parse(ipv4_packet, &self.caps.checksum)); if !self.is_unicast_v4(ipv4_repr.src_addr) && !ipv4_repr.src_addr.is_unspecified() { // Discard packets with non-unicast source addresses but allow unspecified @@ -292,12 +295,15 @@ impl InterfaceInner { } } - pub(super) fn process_icmpv4<'frame>( + pub(super) fn process_icmpv4<'frame, 'socket, S>( &mut self, - _sockets: &mut SocketSet, + _sockets: &mut S, ip_repr: Ipv4Repr, ip_payload: &'frame [u8], - ) -> Option> { + ) -> Option> + where + S: AnySocketSet<'socket>, + { let icmp_packet = check!(Icmpv4Packet::new_checked(ip_payload)); let icmp_repr = check!(Icmpv4Repr::parse(&icmp_packet, &self.caps.checksum)); diff --git a/src/iface/interface/ipv6.rs b/src/iface/interface/ipv6.rs index a72492bb2..a00933ca3 100644 --- a/src/iface/interface/ipv6.rs +++ b/src/iface/interface/ipv6.rs @@ -183,12 +183,15 @@ impl InterfaceInner { }) } - pub(super) fn process_ipv6<'frame>( + pub(super) fn process_ipv6<'frame, 'socket, S>( &mut self, - sockets: &mut SocketSet, + sockets: &mut S, meta: PacketMeta, ipv6_packet: &Ipv6Packet<&'frame [u8]>, - ) -> Option> { + ) -> Option> + where + S: AnySocketSet<'socket>, + { let ipv6_repr = check!(Ipv6Repr::parse(ipv6_packet)); if !ipv6_repr.src_addr.is_unicast() { @@ -297,15 +300,18 @@ impl InterfaceInner { /// Given the next header value forward the payload onto the correct process /// function. - fn process_nxt_hdr<'frame>( + fn process_nxt_hdr<'frame, 'socket, S>( &mut self, - sockets: &mut SocketSet, + sockets: &mut S, meta: PacketMeta, ipv6_repr: Ipv6Repr, nxt_hdr: IpProtocol, handled_by_raw_socket: bool, ip_payload: &'frame [u8], - ) -> Option> { + ) -> Option> + where + S: AnySocketSet<'socket>, + { match nxt_hdr { IpProtocol::Icmpv6 => self.process_icmpv6(sockets, ipv6_repr, ip_payload), @@ -340,12 +346,15 @@ impl InterfaceInner { } } - pub(super) fn process_icmpv6<'frame>( + pub(super) fn process_icmpv6<'frame, 'socket, S>( &mut self, - _sockets: &mut SocketSet, + _sockets: &mut S, ip_repr: Ipv6Repr, ip_payload: &'frame [u8], - ) -> Option> { + ) -> Option> + where + S: AnySocketSet<'socket>, + { let icmp_packet = check!(Icmpv6Packet::new_checked(ip_payload)); let icmp_repr = check!(Icmpv6Repr::parse( &ip_repr.src_addr, diff --git a/src/iface/interface/mod.rs b/src/iface/interface/mod.rs index 697e60ce1..236e2ccbe 100644 --- a/src/iface/interface/mod.rs +++ b/src/iface/interface/mod.rs @@ -40,7 +40,7 @@ use super::fragmentation::{Fragmenter, FragmentsBuffer}; #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))] use super::neighbor::{Answer as NeighborAnswer, Cache as NeighborCache}; -use super::socket_set::SocketSet; +use super::socket_set::AnySocketSet; use crate::config::{ IFACE_MAX_ADDR_COUNT, IFACE_MAX_MULTICAST_GROUP_COUNT, IFACE_MAX_SIXLOWPAN_ADDRESS_CONTEXT_COUNT, @@ -396,14 +396,15 @@ impl Interface { /// This function returns a boolean value indicating whether any packets were /// processed or emitted, and thus, whether the readiness of any socket might /// have changed. - pub fn poll( + pub fn poll<'socket, D, S>( &mut self, timestamp: Instant, device: &mut D, - sockets: &mut SocketSet<'_>, + sockets: &mut S, ) -> bool where D: Device + ?Sized, + S: AnySocketSet<'socket>, { self.inner.now = timestamp; @@ -459,7 +460,10 @@ impl Interface { /// /// [poll]: #method.poll /// [Instant]: struct.Instant.html - pub fn poll_at(&mut self, timestamp: Instant, sockets: &SocketSet<'_>) -> Option { + pub fn poll_at<'socket, S>(&mut self, timestamp: Instant, sockets: &S) -> Option + where + S: AnySocketSet<'socket>, + { self.inner.now = timestamp; #[cfg(feature = "_proto-fragmentation")] @@ -493,7 +497,10 @@ impl Interface { /// /// [poll]: #method.poll /// [Duration]: struct.Duration.html - pub fn poll_delay(&mut self, timestamp: Instant, sockets: &SocketSet<'_>) -> Option { + pub fn poll_delay<'socket, S>(&mut self, timestamp: Instant, sockets: &S) -> Option + where + S: AnySocketSet<'socket>, + { match self.poll_at(timestamp, sockets) { Some(poll_at) if timestamp < poll_at => Some(poll_at - timestamp), Some(_) => Some(Duration::from_millis(0)), @@ -501,9 +508,10 @@ impl Interface { } } - fn socket_ingress(&mut self, device: &mut D, sockets: &mut SocketSet<'_>) -> bool + fn socket_ingress<'socket, D, S>(&mut self, device: &mut D, sockets: &mut S) -> bool where D: Device + ?Sized, + S: AnySocketSet<'socket>, { let mut processed_any = false; @@ -572,9 +580,10 @@ impl Interface { processed_any } - fn socket_egress(&mut self, device: &mut D, sockets: &mut SocketSet<'_>) -> bool + fn socket_egress<'socket, D, S>(&mut self, device: &mut D, sockets: &mut S) -> bool where D: Device + ?Sized, + S: AnySocketSet<'socket>, { let _caps = device.capabilities(); @@ -779,13 +788,16 @@ impl InterfaceInner { } #[cfg(feature = "medium-ip")] - fn process_ip<'frame>( + fn process_ip<'frame, 'socket, S>( &mut self, - sockets: &mut SocketSet, + sockets: &mut S, meta: PacketMeta, ip_payload: &'frame [u8], frag: &'frame mut FragmentsBuffer, - ) -> Option> { + ) -> Option> + where + S: AnySocketSet<'socket>, + { match IpVersion::of_packet(ip_payload) { #[cfg(feature = "proto-ipv4")] Ok(IpVersion::Ipv4) => { @@ -804,12 +816,15 @@ impl InterfaceInner { } #[cfg(feature = "socket-raw")] - fn raw_socket_filter( + fn raw_socket_filter<'socket, S>( &mut self, - sockets: &mut SocketSet, + sockets: &mut S, ip_repr: &IpRepr, ip_payload: &[u8], - ) -> bool { + ) -> bool + where + S: AnySocketSet<'socket>, + { let mut handled_by_raw_socket = false; // Pass every IP packet to all raw sockets we have registered. diff --git a/src/iface/interface/sixlowpan.rs b/src/iface/interface/sixlowpan.rs index 3caa446f5..97bfd6531 100644 --- a/src/iface/interface/sixlowpan.rs +++ b/src/iface/interface/sixlowpan.rs @@ -58,14 +58,17 @@ impl InterfaceInner { tag } - pub(super) fn process_sixlowpan<'output, 'payload: 'output>( + pub(super) fn process_sixlowpan<'output, 'payload: 'output, 'socket, S>( &mut self, - sockets: &mut SocketSet, + sockets: &mut S, meta: PacketMeta, ieee802154_repr: &Ieee802154Repr, payload: &'payload [u8], f: &'output mut FragmentsBuffer, - ) -> Option> { + ) -> Option> + where + S: AnySocketSet<'socket>, + { let payload = match check!(SixlowpanPacket::dispatch(payload)) { #[cfg(not(feature = "proto-sixlowpan-fragmentation"))] SixlowpanPacket::FragmentHeader => { diff --git a/src/iface/interface/tcp.rs b/src/iface/interface/tcp.rs index 85fe0702a..c1b5c96a5 100644 --- a/src/iface/interface/tcp.rs +++ b/src/iface/interface/tcp.rs @@ -3,12 +3,15 @@ use super::*; use crate::socket::tcp::Socket; impl InterfaceInner { - pub(crate) fn process_tcp<'frame>( + pub(crate) fn process_tcp<'frame, 'socket, S>( &mut self, - sockets: &mut SocketSet, + sockets: &mut S, ip_repr: IpRepr, ip_payload: &'frame [u8], - ) -> Option> { + ) -> Option> + where + S: AnySocketSet<'socket>, + { let (src_addr, dst_addr) = (ip_repr.src_addr(), ip_repr.dst_addr()); let tcp_packet = check!(TcpPacket::new_checked(ip_payload)); let tcp_repr = check!(TcpRepr::parse( diff --git a/src/iface/interface/udp.rs b/src/iface/interface/udp.rs index 3c9b0949d..9ec6cb27e 100644 --- a/src/iface/interface/udp.rs +++ b/src/iface/interface/udp.rs @@ -7,14 +7,17 @@ use crate::socket::dns::Socket as DnsSocket; use crate::socket::udp::Socket as UdpSocket; impl InterfaceInner { - pub(super) fn process_udp<'frame>( + pub(super) fn process_udp<'frame, 'socket, S>( &mut self, - sockets: &mut SocketSet, + sockets: &mut S, meta: PacketMeta, handled_by_raw_socket: bool, ip_repr: IpRepr, ip_payload: &'frame [u8], - ) -> Option> { + ) -> Option> + where + S: AnySocketSet<'socket>, + { let (src_addr, dst_addr) = (ip_repr.src_addr(), ip_repr.dst_addr()); let udp_packet = check!(UdpPacket::new_checked(ip_payload)); let udp_repr = check!(UdpRepr::parse( diff --git a/src/iface/mod.rs b/src/iface/mod.rs index 3076088a0..1dd6fdadc 100644 --- a/src/iface/mod.rs +++ b/src/iface/mod.rs @@ -21,4 +21,4 @@ pub use self::interface::MulticastError; pub use self::interface::{Config, Interface, InterfaceInner as Context}; pub use self::route::{Route, RouteTableFull, Routes}; -pub use self::socket_set::{SocketHandle, SocketSet, SocketStorage}; +pub use self::socket_set::{AnySocketSet, SocketHandle, SocketSet, SocketStorage}; diff --git a/src/iface/socket_set.rs b/src/iface/socket_set.rs index be55fef5d..294fe0424 100644 --- a/src/iface/socket_set.rs +++ b/src/iface/socket_set.rs @@ -1,33 +1,58 @@ use core::fmt; -use managed::ManagedSlice; + +use managed::{ManagedSlice, SlotVec}; use super::socket_meta::Meta; use crate::socket::{AnySocket, Socket}; +/// Opaque struct with space for storing one handle. +/// +/// A handle, identifying a socket in an Interface. +/// +/// The [`new`] method can be used to bind a unique index id to a handle, +/// which is usually the index generated when it is added to a socket set +/// so that it can be retrieved from the socket set. Of course, external +/// relationships can also be provided to index the corresponding socket. +/// +/// For simplicity, we do not set the field `handle_id` as a generic input. +/// When customizing the [`AnySocketSet`] implementation, external relations +/// need to decide the conversion themselves. +/// +/// [`new`]: SocketHandle::new +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default, Hash)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct SocketHandle(usize); + /// Opaque struct with space for storing one socket. /// /// This is public so you can use it to allocate space for storing /// sockets when creating an Interface. -#[derive(Debug, Default)] +#[derive(Debug)] pub struct SocketStorage<'a> { - inner: Option>, + pub(crate) meta: Meta, + pub(crate) socket: Socket<'a>, } -impl<'a> SocketStorage<'a> { - pub const EMPTY: Self = Self { inner: None }; -} +/// A set of sockets trait. +/// +/// The lifetime `'a` is used when storing a `Socket<'a>`. +pub trait AnySocketSet<'a> { + /// Returns an iterator over the items in the socket set, immutable version.. + fn items<'s>(&'s self) -> impl Iterator> + where + 'a: 's; -/// An item of a socket set. -#[derive(Debug)] -pub(crate) struct Item<'a> { - pub(crate) meta: Meta, - pub(crate) socket: Socket<'a>, + /// Returns an iterator over the items in the socket set, mutable version. + fn items_mut<'s>(&'s mut self) -> impl Iterator> + where + 'a: 's; } -/// A handle, identifying a socket in an Interface. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default, Hash)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct SocketHandle(usize); +impl SocketHandle { + pub fn new(handle_id: usize) -> Self { + Self(handle_id) + } +} impl fmt::Display for SocketHandle { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -35,23 +60,31 @@ impl fmt::Display for SocketHandle { } } -/// An extensible set of sockets. +impl<'a> SocketStorage<'a> { + pub fn new(handle: SocketHandle, socket: Socket<'a>) -> Self { + let mut meta = Meta::default(); + meta.handle = handle; + Self { meta, socket } + } +} + +/// An extensible set of sockets which implements default [`AnySocketSet`]. /// /// The lifetime `'a` is used when storing a `Socket<'a>`. If you're using /// owned buffers for your sockets (passed in as `Vec`s) you can use /// `SocketSet<'static>`. #[derive(Debug)] pub struct SocketSet<'a> { - sockets: ManagedSlice<'a, SocketStorage<'a>>, + sockets: SlotVec<'a, SocketStorage<'a>>, } impl<'a> SocketSet<'a> { /// Create a socket set using the provided storage. pub fn new(sockets: SocketsT) -> SocketSet<'a> where - SocketsT: Into>>, + SocketsT: Into>>>, { - let sockets = sockets.into(); + let sockets = SlotVec::new(sockets.into()); SocketSet { sockets } } @@ -60,34 +93,16 @@ impl<'a> SocketSet<'a> { /// # Panics /// This function panics if the storage is fixed-size (not a `Vec`) and is full. pub fn add>(&mut self, socket: T) -> SocketHandle { - fn put<'a>(index: usize, slot: &mut SocketStorage<'a>, socket: Socket<'a>) -> SocketHandle { - net_trace!("[{}]: adding", index); - let handle = SocketHandle(index); - let mut meta = Meta::default(); - meta.handle = handle; - *slot = SocketStorage { - inner: Some(Item { meta, socket }), - }; - handle - } - - let socket = socket.upcast(); - - for (index, slot) in self.sockets.iter_mut().enumerate() { - if slot.inner.is_none() { - return put(index, slot, socket); - } - } - - match &mut self.sockets { - ManagedSlice::Borrowed(_) => panic!("adding a socket to a full SocketSet"), - #[cfg(feature = "alloc")] - ManagedSlice::Owned(sockets) => { - sockets.push(SocketStorage { inner: None }); - let index = sockets.len() - 1; - put(index, &mut sockets[index], socket) - } - } + let index = self + .sockets + .push_with(|index| { + net_trace!("[{}]: adding", index); + let handle = SocketHandle::new(index); + let socket = socket.upcast(); + SocketStorage::new(handle, socket) + }) + .expect("adding a socket to a full SocketSet"); + self.sockets[index].meta.handle } /// Get a socket from the set by its handle, as mutable. @@ -96,12 +111,11 @@ impl<'a> SocketSet<'a> { /// This function may panic if the handle does not belong to this socket set /// or the socket has the wrong type. pub fn get>(&self, handle: SocketHandle) -> &T { - match self.sockets[handle.0].inner.as_ref() { - Some(item) => { - T::downcast(&item.socket).expect("handle refers to a socket of a wrong type") - } - None => panic!("handle does not refer to a valid socket"), - } + let item = self + .sockets + .get(handle.0) + .expect("handle does not refer to a valid socket"); + T::downcast(&item.socket).expect("handle refers to a socket of a wrong type") } /// Get a mutable socket from the set by its handle, as mutable. @@ -110,11 +124,11 @@ impl<'a> SocketSet<'a> { /// This function may panic if the handle does not belong to this socket set /// or the socket has the wrong type. pub fn get_mut>(&mut self, handle: SocketHandle) -> &mut T { - match self.sockets[handle.0].inner.as_mut() { - Some(item) => T::downcast_mut(&mut item.socket) - .expect("handle refers to a socket of a wrong type"), - None => panic!("handle does not refer to a valid socket"), - } + let item = self + .sockets + .get_mut(handle.0) + .expect("handle does not refer to a valid socket"); + T::downcast_mut(&mut item.socket).expect("handle refers to a socket of a wrong type") } /// Remove a socket from the set, without changing its state. @@ -123,29 +137,39 @@ impl<'a> SocketSet<'a> { /// This function may panic if the handle does not belong to this socket set. pub fn remove(&mut self, handle: SocketHandle) -> Socket<'a> { net_trace!("[{}]: removing", handle.0); - match self.sockets[handle.0].inner.take() { - Some(item) => item.socket, - None => panic!("handle does not refer to a valid socket"), - } - } - - /// Get an iterator to the inner sockets. - pub fn iter(&self) -> impl Iterator)> { - self.items().map(|i| (i.meta.handle, &i.socket)) + self.sockets + .remove(handle.0) + .map(|item| item.socket) + .expect("handle does not refer to a valid socket") } - /// Get a mutable iterator to the inner sockets. - pub fn iter_mut(&mut self) -> impl Iterator)> { - self.items_mut().map(|i| (i.meta.handle, &mut i.socket)) + /// Checks the handle refers to a valid socket. + /// + /// Returns true if the handle refers to a valid socket, + /// or false if matches any of the following: + /// - the handle does not belong to this socket set, + /// - the handle refers to a socket has the wrong type. + pub fn check>(&self, handle: SocketHandle) -> bool { + self.sockets + .get(handle.0) + .and_then(|item| T::downcast(&item.socket)) + .is_some() } +} - /// Iterate every socket in this set. - pub(crate) fn items(&self) -> impl Iterator> + '_ { - self.sockets.iter().filter_map(|x| x.inner.as_ref()) +/// A default implementation for [`AnySocketSet`]. +impl<'a> AnySocketSet<'a> for SocketSet<'a> { + fn items<'s>(&'s self) -> impl Iterator> + where + 'a: 's, + { + self.sockets.iter() } - /// Iterate every socket in this set. - pub(crate) fn items_mut(&mut self) -> impl Iterator> + '_ { - self.sockets.iter_mut().filter_map(|x| x.inner.as_mut()) + fn items_mut<'s>(&'s mut self) -> impl Iterator> + where + 'a: 's, + { + self.sockets.iter_mut() } }