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: c0629f769ba0
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: 7d54157e77b2
Choose a head ref
  • 2 commits
  • 4 files changed
  • 1 contributor

Commits on Jul 23, 2017

  1. Copy the full SHA
    12f92be View commit details
  2. Add EthernetTracer, a specialization of Tracer for EthernetFrame.

    This makes the loopback example much nicer, #[cfg]-wise.
    whitequark committed Jul 23, 2017
    Copy the full SHA
    7d54157 View commit details
Showing with 83 additions and 35 deletions.
  1. +59 −14 examples/loopback.rs
  2. +18 −19 examples/utils.rs
  3. +3 −0 src/phy/mod.rs
  4. +3 −2 src/phy/tracer.rs
73 changes: 59 additions & 14 deletions examples/loopback.rs
Original file line number Diff line number Diff line change
@@ -3,33 +3,81 @@

#[macro_use]
extern crate log;
extern crate smoltcp;
#[cfg(feature = "std")]
extern crate env_logger;
#[cfg(feature = "std")]
extern crate getopts;
extern crate smoltcp;

#[cfg(feature = "std")]
#[allow(dead_code)]
mod utils;

use smoltcp::Error;
use smoltcp::phy::Loopback;
#[cfg(feature = "std")]
use smoltcp::phy::Tracer;
use smoltcp::phy::EthernetTracer;
use smoltcp::wire::{EthernetAddress, IpAddress};
#[cfg(feature = "std")]
use smoltcp::wire::EthernetFrame;
use smoltcp::iface::{ArpCache, SliceArpCache, EthernetInterface};
use smoltcp::socket::{AsSocket, SocketSet};
use smoltcp::socket::{TcpSocket, TcpSocketBuffer};

#[cfg(not(feature = "std"))]
mod mock {
use core::cell::Cell;

#[derive(Debug)]
pub struct Clock(Cell<u64>);

impl Clock {
pub fn new() -> Clock {
Clock(Cell::new(0))
}

pub fn advance(&self, millis: u64) {
self.0.set(self.0.get() + millis)
}

pub fn elapsed(&self) -> u64 {
self.0.get()
}
}
}

#[cfg(feature = "std")]
mod mock {
use std::sync::Arc;
use std::sync::atomic::{Ordering, AtomicUsize};

// should be AtomicU64 but that's unstable
#[derive(Debug, Clone)]
pub struct Clock(Arc<AtomicUsize>);

impl Clock {
pub fn new() -> Clock {
Clock(Arc::new(AtomicUsize::new(0)))
}

pub fn advance(&self, millis: u64) {
self.0.fetch_add(millis as usize, Ordering::SeqCst);
}

pub fn elapsed(&self) -> u64 {
self.0.load(Ordering::SeqCst) as u64
}
}
}

fn main() {
let clock = mock::Clock::new();

#[cfg(feature = "std")]
utils::setup_logging();
{
let clock = clock.clone();
utils::setup_logging_with_clock(move || clock.elapsed());
}

let mut device = Loopback::new();
#[cfg(feature = "std")]
let mut device = Tracer::<_, EthernetFrame<&'static [u8]>>::new(device, utils::trace_writer);
let mut device = EthernetTracer::new(device, |printer| trace!("{}", printer));

let mut arp_cache_entries: [_; 8] = Default::default();
let mut arp_cache = SliceArpCache::new(&mut arp_cache_entries[..]);
@@ -68,8 +116,7 @@ fn main() {
let mut did_listen = false;
let mut did_connect = false;
let mut done = false;
let mut timestamp_ms = 0;
while !done && timestamp_ms < 500 {
while !done && clock.elapsed() < 10_000 {
{
let socket: &mut TcpSocket = socket_set.get_mut(server_handle).as_socket();
if !socket.is_active() && !socket.is_listening() {
@@ -102,14 +149,12 @@ fn main() {
}
}

match iface.poll(&mut socket_set, timestamp_ms) {
match iface.poll(&mut socket_set, clock.elapsed()) {
Ok(()) | Err(Error::Exhausted) => (),
Err(e) => debug!("poll error: {}", e)
}

const DELAY: u64 = 20;
debug!("{}ms pass", DELAY);
timestamp_ms += DELAY;
clock.advance(1);
}

if !done {
37 changes: 18 additions & 19 deletions examples/utils.rs
Original file line number Diff line number Diff line change
@@ -1,32 +1,27 @@
#![allow(dead_code)]

use std::str::{self, FromStr};
use std::env;
use std::time::{Instant, Duration, SystemTime, UNIX_EPOCH};
use std::process;
use log::{LogLevelFilter, LogRecord};
use log::{LogLevel, LogLevelFilter, LogRecord};
use env_logger::LogBuilder;
use getopts;

use smoltcp::phy::{Tracer, FaultInjector, TapInterface};
use smoltcp::wire::EthernetFrame;
use smoltcp::wire::PrettyPrinter;
use smoltcp::phy::{EthernetTracer, FaultInjector, TapInterface};

pub fn setup_logging() {
let startup_time = Instant::now();
pub fn setup_logging_with_clock<F>(since_startup: F)
where F: Fn() -> u64 + Send + Sync + 'static {
LogBuilder::new()
.format(move |record: &LogRecord| {
let elapsed = Instant::now().duration_since(startup_time);
let timestamp = format!("[{:6}.{:03}s]",
elapsed.as_secs(), elapsed.subsec_nanos() / 1000000);
if record.target().ends_with("::utils") {
let elapsed = since_startup();
let timestamp = format!("[{:6}.{:03}s]", elapsed / 1000, elapsed % 1000);
if record.target().starts_with("smoltcp::") {
format!("\x1b[0m{} ({}): {}\x1b[0m", timestamp,
record.target().replace("smoltcp::", ""), record.args())
} else if record.level() == LogLevel::Trace {
let mut message = format!("{}", record.args());
message.pop();
format!("\x1b[37m{} {}\x1b[0m", timestamp,
message.replace("\n", "\n "))
} else if record.target().starts_with("smoltcp::") {
format!("\x1b[0m{} ({}): {}\x1b[0m", timestamp,
record.target().replace("smoltcp::", ""), record.args())
} else {
format!("\x1b[32m{} ({}): {}\x1b[0m", timestamp,
record.target(), record.args())
@@ -37,12 +32,16 @@ pub fn setup_logging() {
.unwrap();
}

pub fn trace_writer(printer: PrettyPrinter<EthernetFrame<&[u8]>>) {
trace!("{}", printer)
pub fn setup_logging() {
let startup_at = Instant::now();
setup_logging_with_clock(move || {
let elapsed = Instant::now().duration_since(startup_at);
elapsed.as_secs() * 1000 + (elapsed.subsec_nanos() / 1000) as u64
})
}

pub fn setup_device(more_args: &[&str])
-> (FaultInjector<Tracer<TapInterface, EthernetFrame<&'static [u8]>>>,
-> (FaultInjector<EthernetTracer<TapInterface>>,
Vec<String>) {
let mut opts = getopts::Options::new();
opts.optopt("", "drop-chance", "Chance of dropping a packet (%)", "CHANCE");
@@ -79,7 +78,7 @@ pub fn setup_device(more_args: &[&str])
let seed = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().subsec_nanos();

let device = TapInterface::new(&matches.free[0]).unwrap();
let device = Tracer::<_, EthernetFrame<&'static [u8]>>::new(device, trace_writer);
let device = EthernetTracer::new(device, |printer| trace!("{}", printer));
let mut device = FaultInjector::new(device, seed);
device.set_drop_chance(drop_chance);
device.set_corrupt_chance(corrupt_chance);
3 changes: 3 additions & 0 deletions src/phy/mod.rs
Original file line number Diff line number Diff line change
@@ -127,6 +127,9 @@ pub use self::raw_socket::RawSocket;
#[cfg(all(feature = "tap_interface", target_os = "linux"))]
pub use self::tap_interface::TapInterface;

/// A tracer device for Ethernet frames.
pub type EthernetTracer<T> = Tracer<T, super::wire::EthernetFrame<&'static [u8]>>;

/// A description of device limitations.
///
/// Higher-level protocols may achieve higher throughput or lower latency if they consider
5 changes: 3 additions & 2 deletions src/phy/tracer.rs
Original file line number Diff line number Diff line change
@@ -4,8 +4,9 @@ use super::{DeviceLimits, Device};

/// A tracer device.
///
/// A tracer is a device that prints all packets traversing it
/// to the standard output, and delegates to another device otherwise.
/// A tracer is a device that pretty prints all packets traversing it
/// using the provided writer function, and then passes them to another
/// device.
pub struct Tracer<T: Device, U: PrettyPrint> {
lower: T,
writer: fn(PrettyPrinter<U>)