Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: smoltcp-rs/smoltcp
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 3377b911d84b
Choose a base ref
...
head repository: smoltcp-rs/smoltcp
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 59dae01e9c4d
Choose a head ref
  • 2 commits
  • 8 files changed
  • 1 contributor

Commits on Dec 15, 2016

  1. Copy the full SHA
    8ff9b17 View commit details

Commits on Dec 17, 2016

  1. Copy the full SHA
    59dae01 View commit details
Showing with 262 additions and 170 deletions.
  1. +5 −4 examples/smoltcpserver.rs
  2. +16 −23 src/iface/arp_cache.rs
  3. +6 −1 src/iface/ethernet.rs
  4. +6 −2 src/lib.rs
  5. +80 −0 src/managed.rs
  6. +3 −7 src/socket/mod.rs
  7. +144 −133 src/socket/udp.rs
  8. +2 −0 src/wire/ip.rs
9 changes: 5 additions & 4 deletions examples/smoltcpserver.rs
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@ use std::env;
use smoltcp::phy::{Tracer, TapInterface};
use smoltcp::wire::{EthernetFrame, EthernetAddress, InternetAddress, InternetEndpoint};
use smoltcp::iface::{SliceArpCache, EthernetInterface};
use smoltcp::socket::{Socket, UdpSocket, UdpUnitaryBuffer};
use smoltcp::socket::{Socket, UdpSocket, UdpBuffer, UdpBufferElem};

fn main() {
let ifname = env::args().nth(1).unwrap();
@@ -20,13 +20,14 @@ fn main() {
let listen_address = InternetAddress::ipv4([0, 0, 0, 0]);
let endpoint = InternetEndpoint::new(listen_address, 6969);

let udp_rx_buffer = UdpUnitaryBuffer::new(vec![0; 2048]);
let udp_tx_buffer = UdpUnitaryBuffer::new(vec![0; 2048]);
let udp_rx_buffer = UdpBuffer::new(vec![UdpBufferElem::new(vec![0; 2048])]);
let udp_tx_buffer = UdpBuffer::new(vec![UdpBufferElem::new(vec![0; 2048])]);
let mut udp_socket = UdpSocket::new(endpoint, udp_rx_buffer, udp_tx_buffer);
let mut sockets: [&mut Socket; 1] = [&mut udp_socket];

let mut sockets: [&mut Socket; 1] = [&mut udp_socket];
let mut iface = EthernetInterface::new(device, arp_cache,
hardware_addr, &mut protocol_addrs[..], &mut sockets[..]);

loop {
match iface.poll() {
Ok(()) => (),
39 changes: 16 additions & 23 deletions src/iface/arp_cache.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use core::borrow::BorrowMut;

use Managed;
use wire::{EthernetAddress, InternetAddress};

/// An Address Resolution Protocol cache.
@@ -33,26 +32,24 @@ pub trait Cache {
/// let mut arp_cache = SliceArpCache::new(&mut arp_cache_storage[..]);
/// ```
pub struct SliceCache<
StorageT: BorrowMut<[(InternetAddress, EthernetAddress, usize)]>
> {
storage: StorageT,
pub struct SliceCache<'a> {
storage: Managed<'a, [(InternetAddress, EthernetAddress, usize)]>,
counter: usize
}

impl<
StorageT: BorrowMut<[(InternetAddress, EthernetAddress, usize)]>
> SliceCache<StorageT> {
impl<'a> SliceCache<'a> {
/// Create a cache. The backing storage is cleared upon creation.
///
/// # Panics
/// This function panics if `storage.len() == 0`.
pub fn new(mut storage: StorageT) -> SliceCache<StorageT> {
if storage.borrow().len() == 0 {
pub fn new<T>(storage: T) -> SliceCache<'a>
where T: Into<Managed<'a, [(InternetAddress, EthernetAddress, usize)]>> {
let mut storage = storage.into();
if storage.len() == 0 {
panic!("ARP slice cache created with empty storage")
}

for elem in storage.borrow_mut().iter_mut() {
for elem in storage.iter_mut() {
*elem = Default::default()
}
SliceCache {
@@ -65,30 +62,25 @@ impl<
fn find(&self, protocol_addr: InternetAddress) -> Option<usize> {
// The order of comparison is important: any valid InternetAddress should
// sort before InternetAddress::Invalid.
let storage = self.storage.borrow();
storage.binary_search_by_key(&protocol_addr, |&(key, _, _)| key).ok()
self.storage.binary_search_by_key(&protocol_addr, |&(key, _, _)| key).ok()
}

/// Sort entries in an order suitable for `find`.
fn sort(&mut self) {
let mut storage = self.storage.borrow_mut();
storage.sort_by_key(|&(key, _, _)| key)
self.storage.sort_by_key(|&(key, _, _)| key)
}

/// Find the least recently used entry.
fn lru(&self) -> usize {
let storage = self.storage.borrow();
storage.iter().enumerate().min_by_key(|&(_, &(_, _, counter))| counter).unwrap().0
self.storage.iter().enumerate().min_by_key(|&(_, &(_, _, counter))| counter).unwrap().0
}
}

impl<
StorageT: BorrowMut<[(InternetAddress, EthernetAddress, usize)]>
> Cache for SliceCache<StorageT> {
impl<'a> Cache for SliceCache<'a> {
fn fill(&mut self, protocol_addr: InternetAddress, hardware_addr: EthernetAddress) {
if let None = self.find(protocol_addr) {
let lru_index = self.lru();
self.storage.borrow_mut()[lru_index] =
self.storage[lru_index] =
(protocol_addr, hardware_addr, self.counter);
self.sort()
}
@@ -97,7 +89,7 @@ impl<
fn lookup(&mut self, protocol_addr: InternetAddress) -> Option<EthernetAddress> {
if let Some(index) = self.find(protocol_addr) {
let (_protocol_addr, hardware_addr, ref mut counter) =
self.storage.borrow_mut()[index];
self.storage[index];
self.counter += 1;
*counter = self.counter;
Some(hardware_addr)
@@ -146,3 +138,4 @@ mod test {
assert_eq!(cache.lookup(PADDR_D), Some(HADDR_D));
}
}

7 changes: 6 additions & 1 deletion src/iface/ethernet.rs
Original file line number Diff line number Diff line change
@@ -99,12 +99,17 @@ impl<'a,
Self::check_protocol_addrs(self.protocol_addrs.borrow())
}

/// Checks whether the interface has the given protocol address assigned.
/// Check whether the interface has the given protocol address assigned.
pub fn has_protocol_addr<T: Into<InternetAddress>>(&self, addr: T) -> bool {
let addr = addr.into();
self.protocol_addrs.borrow().iter().any(|&probe| probe == addr)
}

/// Get the set of sockets owned by the interface.
pub fn with_sockets<R, F: FnOnce(&mut [&'a mut Socket]) -> R>(&mut self, f: F) -> R {
f(self.sockets.borrow_mut())
}

/// Receive and process a packet, if available.
pub fn poll(&mut self) -> Result<(), Error> {
enum Response<'a> {
8 changes: 6 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![feature(associated_consts, const_fn, step_by)]
#![feature(associated_consts, const_fn, step_by, intrinsics)]
#![no_std]

extern crate byteorder;
@@ -11,13 +11,17 @@ extern crate libc;

use core::fmt;

mod managed;

pub mod phy;
pub mod wire;
pub mod iface;
pub mod socket;

pub use managed::Managed;

/// The error type for the networking stack.
#[derive(Debug)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Error {
/// An incoming packet could not be parsed, or an outgoing packet could not be emitted
/// because a field was out of bounds for the underlying buffer.
80 changes: 80 additions & 0 deletions src/managed.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
use core::ops::{Deref, DerefMut};
use core::borrow::BorrowMut;
use core::fmt;

#[cfg(feature = "std")]
use std::boxed::Box;
#[cfg(feature = "std")]
use std::vec::Vec;

/// A managed object.
///
/// This enum can be used to represent exclusive access to objects. In Rust, exclusive access
/// to an object is obtained by either owning the object, or owning a mutable pointer
/// to the object; hence, "managed".
///
/// The purpose of this enum is providing good ergonomics with `std` present while making
/// it possible to avoid having a heap at all (which of course means that `std` is not present).
/// To achieve this, the `Managed::Owned` variant is only available when the "std" feature
/// is enabled.
///
/// A function that requires a managed object should be generic over an `Into<Managed<'a, T>>`
/// argument; then, it will be possible to pass either a `Box<T>`, `Vec<T>`, or a `&'a mut T`
/// without any conversion at the call site.
pub enum Managed<'a, T: 'a + ?Sized> {
/// Borrowed variant, either a single element or a slice.
Borrowed(&'a mut T),
/// Owned variant, only available with `std` present.
#[cfg(feature = "std")]
Owned(Box<BorrowMut<T>>)
}

impl<'a, T: 'a + fmt::Debug + ?Sized> fmt::Debug for Managed<'a, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Managed::from({:?})", self.deref())
}
}

impl<'a, T: 'a + ?Sized> From<&'a mut T> for Managed<'a, T> {
fn from(value: &'a mut T) -> Self {
Managed::Borrowed(value)
}
}

#[cfg(feature = "std")]
impl<T, U: BorrowMut<T> + 'static> From<Box<U>> for Managed<'static, T> {
fn from(value: Box<U>) -> Self {
Managed::Owned(value)
}
}

#[cfg(feature = "std")]
impl<T: 'static> From<Vec<T>> for Managed<'static, [T]> {
fn from(mut value: Vec<T>) -> Self {
value.shrink_to_fit();
Managed::Owned(Box::new(value))
}
}

impl<'a, T: 'a + ?Sized> Deref for Managed<'a, T> {
type Target = T;

fn deref(&self) -> &Self::Target {
match self {
&Managed::Borrowed(ref value) => value,
#[cfg(feature = "std")]
&Managed::Owned(ref value) => (**value).borrow()
}
}
}

impl<'a, T: 'a + ?Sized> DerefMut for Managed<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
match self {
&mut Managed::Borrowed(ref mut value) => value,
#[cfg(feature = "std")]
&mut Managed::Owned(ref mut value) => (**value).borrow_mut()
}
}
}

10 changes: 3 additions & 7 deletions src/socket/mod.rs
Original file line number Diff line number Diff line change
@@ -9,19 +9,14 @@
//! the operating system decides on the good size for a buffer and manages it.
//! The interface implemented by this module uses explicit buffering: you decide on the good
//! size for a buffer, allocate it, and let the networking stack use it.
//!
//! Every socket implementation allows selecting transmit and receive buffers separately;
//! this means that, for example, a socket that never receives data does not have to allocate
//! any storage to receive buffers.
use Error;
use wire::{InternetAddress as Address, InternetProtocolType as ProtocolType};

mod udp;

pub use self::udp::Buffer as UdpBuffer;
pub use self::udp::NullBuffer as UdpNullBuffer;
pub use self::udp::UnitaryBuffer as UdpUnitaryBuffer;
pub use self::udp::BufferElem as UdpBufferElem;
pub use self::udp::UdpSocket as UdpSocket;

/// A packet representation.
@@ -40,7 +35,8 @@ pub trait PacketRepr {
///
/// This interface abstracts the various types of sockets based on the IP protocol.
/// It is necessarily implemented as a trait, and not as an enumeration, to allow using different
/// buffering strategies in sockets assigned to the same interface.
/// buffer types in sockets assigned to the same interface. To access a socket through this
/// interface, cast it using `.as::<T>()`.
///
/// The `collect` and `dispatch` functions are fundamentally asymmetric and thus differ in
/// their use of the [trait PacketRepr](trait.PacketRepr.html). When `collect` is called,
Loading