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: 9a4efcd656dd
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: 15ce66774323
Choose a head ref
  • 2 commits
  • 6 files changed
  • 1 contributor

Commits on Jul 14, 2017

  1. Remove default impl for Device::limits().

    We should not assume any default MTU.
    whitequark committed Jul 14, 2017
    Copy the full SHA
    042019d View commit details
  2. Copy the full SHA
    15ce667 View commit details
Showing with 160 additions and 12 deletions.
  1. +4 −1 Cargo.toml
  2. +22 −2 README.md
  3. +118 −0 examples/loopback.rs
  4. +7 −5 examples/utils.rs
  5. +8 −1 src/phy/loopback.rs
  6. +1 −3 src/phy/mod.rs
5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -25,7 +25,7 @@ getopts = "0.2"
[features]
std = ["managed/std"]
alloc = ["managed/alloc"]
collections = ["managed/collections"]
collections = ["alloc", "managed/collections"]
verbose = []
raw_socket = ["libc"]
tap_interface = ["libc"]
@@ -42,3 +42,6 @@ name = "client"

[[example]]
name = "ping"

[[example]]
name = "loopback"
24 changes: 22 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -125,8 +125,8 @@ or `BufWriter` is used, which are of course not available on heap-less systems.

This feature is disabled by default.

Usage example
-------------
Hosted usage examples
---------------------

_smoltcp_, being a freestanding networking stack, needs to be able to transmit and receive
raw frames. For testing purposes, we will use a regular OS, and run _smoltcp_ in
@@ -240,6 +240,26 @@ Currently, netmasks are not implemented, and so the only address this example ca
is the other endpoint of the tap interface, `192.168.1.100`. It cannot reach itself because
packets entering a tap interface do not loop back.

Bare-metal usage examples
-------------------------

Examples that use no services from the host OS are necessarily less illustrative than examples
that do. Because of this, only one such example is provided.

### examples/loopback.rs

_examples/loopback.rs_ performs a simple exchange between two TCP socket via a loopback interface.
This example requires the `collections` feature to run.

Read its [source code](/examples/loopback.rs), then run it as:

```sh
cargo run --example loopback
```

If the `std` feature is enabled, it will print logs and packet dumps; otherwise, nothing at all
will be displayed.

License
-------

118 changes: 118 additions & 0 deletions examples/loopback.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
#![cfg_attr(not(feature = "std"), no_std)]
#![allow(unused_mut)]

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

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

use smoltcp::Error;
use smoltcp::phy::Loopback;
#[cfg(feature = "std")]
use smoltcp::phy::Tracer;
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};

fn main() {
#[cfg(feature = "std")]
utils::setup_logging();

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

let mut arp_cache_entries: [_; 8] = Default::default();
let mut arp_cache = SliceArpCache::new(&mut arp_cache_entries[..]);

let hardware_addr = EthernetAddress::default();
let mut protocol_addrs = [IpAddress::v4(127, 0, 0, 1)];
let mut iface = EthernetInterface::new(
&mut device, &mut arp_cache as &mut ArpCache,
hardware_addr, &mut protocol_addrs[..]);

let server_socket = {
// It is not strictly necessary to use a `static mut` and unsafe code here, but
// on embedded systems that smoltcp targets it is far better to allocate the data
// statically to verify that it fits into RAM rather than get undefined behavior
// when stack overflows.
static mut TCP_SERVER_RX_DATA: [u8; 1024] = [0; 1024];
static mut TCP_SERVER_TX_DATA: [u8; 1024] = [0; 1024];
let tcp_rx_buffer = TcpSocketBuffer::new(unsafe { &mut TCP_SERVER_RX_DATA[..] });
let tcp_tx_buffer = TcpSocketBuffer::new(unsafe { &mut TCP_SERVER_TX_DATA[..] });
TcpSocket::new(tcp_rx_buffer, tcp_tx_buffer)
};

let client_socket = {
static mut TCP_CLIENT_RX_DATA: [u8; 1024] = [0; 1024];
static mut TCP_CLIENT_TX_DATA: [u8; 1024] = [0; 1024];
let tcp_rx_buffer = TcpSocketBuffer::new(unsafe { &mut TCP_CLIENT_RX_DATA[..] });
let tcp_tx_buffer = TcpSocketBuffer::new(unsafe { &mut TCP_CLIENT_TX_DATA[..] });
TcpSocket::new(tcp_rx_buffer, tcp_tx_buffer)
};

let mut socket_set_entries: [_; 2] = Default::default();
let mut socket_set = SocketSet::new(&mut socket_set_entries[..]);
let server_handle = socket_set.add(server_socket);
let client_handle = socket_set.add(client_socket);

let mut did_listen = false;
let mut did_connect = false;
let mut done = false;
let mut timestamp_ms = 0;
while !done && timestamp_ms < 500 {
{
let socket: &mut TcpSocket = socket_set.get_mut(server_handle).as_socket();
if !socket.is_active() && !socket.is_listening() {
if !did_listen {
socket.listen(1234).unwrap();
did_listen = true;
}
}

if socket.can_recv() {
debug!("got {:?}", socket.recv(32).unwrap());
socket.close();
done = true;
}
}

{
let socket: &mut TcpSocket = socket_set.get_mut(client_handle).as_socket();
if !socket.is_open() {
if !did_connect {
socket.connect((IpAddress::v4(127, 0, 0, 1), 1234),
(IpAddress::v4(127, 0, 0, 1), 65000)).unwrap();
did_connect = true;
}
}

if socket.can_send() {
socket.send_slice(b"0123456789abcdef").unwrap();
socket.close();
}
}

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

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

if !done {
error!("this is taking too long, bailing out");
}
}
12 changes: 7 additions & 5 deletions examples/utils.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
#![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 env_logger::{LogBuilder};
use env_logger::LogBuilder;
use getopts;

use smoltcp::phy::{Tracer, FaultInjector, TapInterface};
@@ -35,6 +37,10 @@ pub fn setup_logging() {
.unwrap();
}

pub fn trace_writer(printer: PrettyPrinter<EthernetFrame<&[u8]>>) {
trace!("{}", printer)
}

pub fn setup_device(more_args: &[&str])
-> (FaultInjector<Tracer<TapInterface, EthernetFrame<&'static [u8]>>>,
Vec<String>) {
@@ -72,10 +78,6 @@ pub fn setup_device(more_args: &[&str])

let seed = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().subsec_nanos();

fn trace_writer(printer: PrettyPrinter<EthernetFrame<&[u8]>>) {
trace!("{}", printer)
}

let device = TapInterface::new(&matches.free[0]).unwrap();
let device = Tracer::<_, EthernetFrame<&'static [u8]>>::new(device, trace_writer);
let mut device = FaultInjector::new(device, seed);
9 changes: 8 additions & 1 deletion src/phy/loopback.rs
Original file line number Diff line number Diff line change
@@ -12,7 +12,7 @@ use std::collections::VecDeque;
use collections::{Vec, VecDeque};

use Error;
use super::Device;
use super::{Device, DeviceLimits};

/// A loopback interface.
#[derive(Debug)]
@@ -32,6 +32,13 @@ impl Device for Loopback {
type RxBuffer = Vec<u8>;
type TxBuffer = TxBuffer;

fn limits(&self) -> DeviceLimits {
DeviceLimits {
max_transmission_unit: 65535,
..DeviceLimits::default()
}
}

fn receive(&mut self) -> Result<Self::RxBuffer, Error> {
match self.0.borrow_mut().pop_front() {
Some(packet) => Ok(packet),
4 changes: 1 addition & 3 deletions src/phy/mod.rs
Original file line number Diff line number Diff line change
@@ -162,9 +162,7 @@ pub trait Device {
type TxBuffer: AsRef<[u8]> + AsMut<[u8]>;

/// Get a description of device limitations.
fn limits(&self) -> DeviceLimits {
DeviceLimits::default()
}
fn limits(&self) -> DeviceLimits;

/// Receive a frame.
///