ethox 0.0.2

A standalone network stack for user-space networking and unikernels
Documentation
//! A simplified curl.
//!
//! Connects to a given remote tcp/http host and requests the root page, then prints the response
//! without headers. Can handle up to 1MB of response data.
use std::io::{stdout, Write};
use structopt::StructOpt;

use ethox::managed::{List, Map, SlotMap, Slice};
use ethox::nic::{Device, sys::RawSocket, Protocol};
use ethox::layer::{arp, eth, ip, tcp};
use ethox::wire::{ip::v4, ethernet};

fn main() {
    let Config {
        name,
        host,
        hostmac,
        gateway,
        server,
        server_port,
    } = Config::from_args();

    let mut eth = eth::Endpoint::new(hostmac);

    // Buffer space for arp neighbor cache
    let mut neighbors = [arp::Neighbor::default(); 1];
    // Buffer space for routes, we only have a single state one.
    let mut routes = [ip::Route::new_ipv4_gateway(gateway.address()); 1];
    let mut ip = ip::Endpoint::new(Slice::One(host.into()),
        ip::Routes::import(List::new_full(routes.as_mut().into())),
        arp::NeighborCache::new(&mut neighbors[..]));

    let mut tcp = tcp::Endpoint::new(
        Map::Pairs(List::new(Slice::One(Default::default()))),
        SlotMap::new(Slice::One(Default::default()), Slice::One(Default::default())),
        tcp::IsnGenerator::from_std_hash(),
    );

    let message = "GET / HTTP/1.0\r\n\r\n";
    let mut tcp_client = tcp::Client::new(
        v4::Address::from(server).into(), server_port,
        tcp::io::RecvInto::new(vec![0; 1 << 20]),
        tcp::io::SendFrom::once(message.as_bytes()));

    let mut interface = RawSocket::new(&name, vec![0; 1 << 14])
        .expect(&format!("Couldn't initialize interface {}", name));
    *interface.capabilities_mut().tcp_mut() = Protocol::offloaded().into();

    let out = stdout();
    let mut out = out.lock();

    loop {
        let rx = interface.rx(10, eth.recv(ip.recv(tcp.recv(&mut tcp_client)))).unwrap();
        let tx = interface.tx(10, eth.send(ip.send(tcp.send(&mut tcp_client)))).unwrap();

        if tcp_client.is_closed() {
            break;
        }
    }

    let received = tcp_client.recv().received();
    let http = String::from_utf8_lossy(received);
    let header_end = http.find("\r\n\r\n")
        .expect(&format!("Expected http header end in {}", http));
    write!(out, "{}", &http[header_end+4..])
        .unwrap();
}

#[derive(StructOpt)]
struct Config {
    name: String,
    host: v4::Cidr,
    hostmac: ethernet::Address,
    gateway: v4::Cidr,
    server: std::net::Ipv4Addr,
    server_port: u16,
}