use core::{fmt, slice}; use managed::ManagedSlice; #[cfg(feature = "socket-tcp")] use crate::socket::TcpState; use crate::socket::{AnySocket, Socket}; /// An item of a socket set. /// /// The only reason this struct is public is to allow the socket set storage /// to be allocated externally. #[derive(Debug)] pub struct Item<'a> { socket: Socket<'a>, refs: usize, } /// A handle, identifying a socket in a set. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default, Hash)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct Handle(usize); impl fmt::Display for Handle { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "#{}", self.0) } } /// An extensible set of sockets. /// /// The lifetime `'a` is used when storing a `Socket<'a>`. #[derive(Debug)] pub struct Set<'a> { sockets: ManagedSlice<'a, Option>>, } impl<'a> Set<'a> { /// Create a socket set using the provided storage. pub fn new(sockets: SocketsT) -> Set<'a> where SocketsT: Into>>>, { let sockets = sockets.into(); Set { sockets } } /// Add a socket to the set with the reference count 1, and return its handle. /// /// # Panics /// This function panics if the storage is fixed-size (not a `Vec`) and is full. pub fn add(&mut self, socket: T) -> Handle where T: Into>, { fn put<'a>(index: usize, slot: &mut Option>, mut socket: Socket<'a>) -> Handle { net_trace!("[{}]: adding", index); let handle = Handle(index); socket.meta_mut().handle = handle; *slot = Some(Item { socket, refs: 1 }); handle } let socket = socket.into(); for (index, slot) in self.sockets.iter_mut().enumerate() { if slot.is_none() { return put(index, slot, socket); } } match self.sockets { ManagedSlice::Borrowed(_) => panic!("adding a socket to a full SocketSet"), #[cfg(any(feature = "std", feature = "alloc"))] ManagedSlice::Owned(ref mut sockets) => { sockets.push(None); let index = sockets.len() - 1; put(index, &mut sockets[index], socket) } } } /// Get a socket from the set by its handle, as mutable. /// /// # Panics /// 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 self, handle: Handle) -> &mut T { match self.sockets[handle.0].as_mut() { Some(item) => { T::downcast(&mut item.socket).expect("handle refers to a socket of a wrong type") } None => panic!("handle does not refer to a valid socket"), } } /// Remove a socket from the set, without changing its state. /// /// # Panics /// This function may panic if the handle does not belong to this socket set. pub fn remove(&mut self, handle: Handle) -> Socket<'a> { net_trace!("[{}]: removing", handle.0); match self.sockets[handle.0].take() { Some(item) => item.socket, None => panic!("handle does not refer to a valid socket"), } } /// Increase reference count by 1. /// /// # Panics /// This function may panic if the handle does not belong to this socket set. pub fn retain(&mut self, handle: Handle) { self.sockets[handle.0] .as_mut() .expect("handle does not refer to a valid socket") .refs += 1 } /// Decrease reference count by 1. /// /// # Panics /// This function may panic if the handle does not belong to this socket set, /// or if the reference count is already zero. pub fn release(&mut self, handle: Handle) { let refs = &mut self.sockets[handle.0] .as_mut() .expect("handle does not refer to a valid socket") .refs; if *refs == 0 { panic!("decreasing reference count past zero") } *refs -= 1 } /// Prune the sockets in this set. /// /// Pruning affects sockets with reference count 0. Open sockets are closed. /// Closed sockets are removed and dropped. pub fn prune(&mut self) { for (index, item) in self.sockets.iter_mut().enumerate() { let mut may_remove = false; if let Some(Item { refs: 0, ref mut socket, }) = *item { match *socket { #[cfg(feature = "socket-raw")] Socket::Raw(_) => may_remove = true, #[cfg(all( feature = "socket-icmp", any(feature = "proto-ipv4", feature = "proto-ipv6") ))] Socket::Icmp(_) => may_remove = true, #[cfg(feature = "socket-udp")] Socket::Udp(_) => may_remove = true, #[cfg(feature = "socket-tcp")] Socket::Tcp(ref mut socket) => { if socket.state() == TcpState::Closed { may_remove = true } else { socket.close() } } #[cfg(feature = "socket-dhcpv4")] Socket::Dhcpv4(_) => may_remove = true, } } if may_remove { net_trace!("[{}]: pruning", index); *item = None } } } /// Iterate every socket in this set. pub fn iter<'d>(&'d self) -> Iter<'d, 'a> { Iter { lower: self.sockets.iter(), } } /// Iterate every socket in this set. pub fn iter_mut<'d>(&'d mut self) -> IterMut<'d, 'a> { IterMut { lower: self.sockets.iter_mut(), } } } /// Immutable socket set iterator. /// /// This struct is created by the [iter](struct.SocketSet.html#method.iter) /// on [socket sets](struct.SocketSet.html). pub struct Iter<'a, 'b: 'a> { lower: slice::Iter<'a, Option>>, } impl<'a, 'b: 'a> Iterator for Iter<'a, 'b> { type Item = &'a Socket<'b>; fn next(&mut self) -> Option { for item_opt in &mut self.lower { if let Some(item) = item_opt.as_ref() { return Some(&item.socket); } } None } } /// Mutable socket set iterator. /// /// This struct is created by the [iter_mut](struct.SocketSet.html#method.iter_mut) /// on [socket sets](struct.SocketSet.html). pub struct IterMut<'a, 'b: 'a> { lower: slice::IterMut<'a, Option>>, } impl<'a, 'b: 'a> Iterator for IterMut<'a, 'b> { type Item = &'a mut Socket<'b>; fn next(&mut self) -> Option { for item_opt in &mut self.lower { if let Some(item) = item_opt.as_mut() { return Some(&mut item.socket); } } None } }