Skip to content

Commit

Permalink
Rust: implement bindings for lwip TCP/UDP stacks.
Browse files Browse the repository at this point in the history
whitequark committed Sep 6, 2016
1 parent 5d293d1 commit bf86305
Showing 10 changed files with 675 additions and 68 deletions.
41 changes: 15 additions & 26 deletions artiq/runtime.rs/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 2 additions & 5 deletions artiq/runtime.rs/Cargo.toml
Original file line number Diff line number Diff line change
@@ -10,11 +10,8 @@ path = "src/lib.rs"

[dependencies]
std_artiq = { path = "libstd_artiq" }

[dependencies.fringe]
git = "https://github.com/whitequark/libfringe"
default-features = false
features = ["alloc"]
fringe = { version = "1.0.5", default-features = false, features = ["alloc"] }
lwip = { path = "liblwip" }

[profile.dev]
panic = 'abort'
8 changes: 8 additions & 0 deletions artiq/runtime.rs/liblwip-sys/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[package]
authors = ["The ARTIQ Project Developers"]
name = "lwip-sys"
version = "0.0.0"

[lib]
name = "lwip_sys"
path = "lib.rs"
160 changes: 160 additions & 0 deletions artiq/runtime.rs/liblwip-sys/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
#![no_std]
#![feature(libc)]
#![allow(non_camel_case_types)]

extern crate libc;

pub use err::*;
pub use pbuf_layer::*;
pub use pbuf_type::*;
pub use ip_addr_type::*;

use libc::{c_void, c_int};

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(i8)]
pub enum err {
ERR_OK = 0,
ERR_MEM = -1,
ERR_BUF = -2,
ERR_TIMEOUT = -3,
ERR_RTE = -4,
ERR_INPROGRESS = -5,
ERR_VAL = -6,
ERR_WOULDBLOCK = -7,
ERR_USE = -8,
ERR_ALREADY = -9,
ERR_ISCONN = -10,
ERR_CONN = -11,
ERR_IF = -12,
ERR_ABRT = -13,
ERR_RST = -14,
ERR_CLSD = -15,
ERR_ARG = -16,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum pbuf_layer {
PBUF_TRANSPORT,
PBUF_IP,
PBUF_LINK,
PBUF_RAW_TX,
PBUF_RAW
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum pbuf_type {
PBUF_RAM,
PBUF_ROM,
PBUF_REF,
PBUF_POOL,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum ip_addr_type {
IPADDR_TYPE_V4 = 0,
IPADDR_TYPE_V6 = 6,
IPADDR_TYPE_ANY = 46,
}

#[repr(C)]
pub struct pbuf {
pub next: *mut pbuf,
pub payload: *mut c_void,
pub tot_len: u16,
pub len: u16,
pub type_: pbuf_type,
pub flags: u8,
pub ref_: u16
}

#[derive(Clone)]
#[repr(C)]
pub struct ip4_addr {
pub addr: u32
}

#[derive(Clone)]
#[repr(C)]
pub struct ip6_addr {
pub addr: [u32; 4]
}

#[derive(Clone)]
#[repr(C)]
pub struct ip_addr {
pub data: [u32; 4],
pub type_: ip_addr_type
}

#[repr(C)]
pub struct tcp_pcb {
__opaque: c_void
}

#[repr(C)]
pub struct udp_pcb {
__opaque: c_void
}

pub const TCP_WRITE_FLAG_COPY: u8 = 0x01;
pub const TCP_WRITE_FLAG_MORE: u8 = 0x02;

extern {
pub fn pbuf_alloc(l: pbuf_layer, length: u16, type_: pbuf_type) -> *mut pbuf;
pub fn pbuf_realloc(p: *mut pbuf, length: u16);
pub fn pbuf_ref(p: *mut pbuf);
pub fn pbuf_free(p: *mut pbuf);
pub fn pbuf_cat(head: *mut pbuf, tail: *mut pbuf);
pub fn pbuf_chain(head: *mut pbuf, tail: *mut pbuf);
pub fn pbuf_dechain(p: *mut pbuf) -> *mut pbuf;
pub fn pbuf_copy(p_to: *mut pbuf, p_from: *mut pbuf) -> err;
pub fn pbuf_copy_partial(p: *mut pbuf, dataptr: *mut c_void, len: u16, offset: u16) -> u16;
pub fn pbuf_take(p: *mut pbuf, dataptr: *const c_void, len: u16) -> err;
pub fn pbuf_take_at(p: *mut pbuf, dataptr: *const c_void, len: u16, offset: u16) -> err;
pub fn pbuf_skip(in_: *mut pbuf, in_offset: u16, out_offset: *mut u16) -> *mut pbuf;

pub fn tcp_new() -> *mut tcp_pcb;
pub fn tcp_arg(pcb: *mut tcp_pcb, arg: *mut c_void);
pub fn tcp_bind(pcb: *mut tcp_pcb, ipaddr: *mut ip_addr, port: u16) -> err;
pub fn tcp_listen_with_backlog(pcb: *mut tcp_pcb, backlog: u8) -> *mut tcp_pcb;
pub fn tcp_accept(pcb: *mut tcp_pcb,
accept: extern fn(arg: *mut c_void, newpcb: *mut tcp_pcb,
err: err) -> err);
pub fn tcp_connect(pcb: *mut tcp_pcb, ipaddr: *mut ip_addr, port: u16,
connected: extern fn(arg: *mut c_void, tcb: *mut tcp_pcb, err: err)) -> err;
pub fn tcp_write(pcb: *mut tcp_pcb, dataptr: *const c_void, len: u16, apiflags: u8) -> err;
pub fn tcp_sent(pcb: *mut tcp_pcb,
sent: extern fn(arg: *mut c_void, tcb: *mut tcp_pcb, len: u16) -> err);
pub fn tcp_recv(pcb: *mut tcp_pcb,
recv: extern fn(arg: *mut c_void, tcb: *mut tcp_pcb, p: *mut pbuf,
err: err) -> err);
pub fn tcp_recved(pcb: *mut tcp_pcb, len: u16);
pub fn tcp_poll(pcb: *mut tcp_pcb,
poll: extern fn(arg: *mut c_void, tcb: *mut tcp_pcb),
interval: u8);
pub fn tcp_shutdown(pcb: *mut tcp_pcb, shut_rx: c_int, shut_tx: c_int) -> err;
pub fn tcp_close(pcb: *mut tcp_pcb) -> err;
pub fn tcp_abort(pcb: *mut tcp_pcb);
pub fn tcp_err(pcb: *mut tcp_pcb,
err: extern fn(arg: *mut c_void, err: err));

// nonstandard
pub fn tcp_sndbuf_(pcb: *mut tcp_pcb) -> u16;

pub fn udp_new() -> *mut udp_pcb;
pub fn udp_new_ip_type(type_: ip_addr_type) -> *mut udp_pcb;
pub fn udp_remove(pcb: *mut udp_pcb);
pub fn udp_bind(pcb: *mut udp_pcb, ipaddr: *mut ip_addr, port: u16) -> err;
pub fn udp_connect(pcb: *mut udp_pcb, ipaddr: *mut ip_addr, port: u16) -> err;
pub fn udp_disconnect(pcb: *mut udp_pcb) -> err;
pub fn udp_send(pcb: *mut udp_pcb, p: *mut pbuf) -> err;
pub fn udp_sendto(pcb: *mut udp_pcb, p: *mut pbuf, ipaddr: *mut ip_addr, port: u16) -> err;
pub fn udp_recv(pcb: *mut udp_pcb,
recv: extern fn(arg: *mut c_void, upcb: *mut udp_pcb, p: *mut pbuf,
addr: *mut ip_addr, port: u16),
recv_arg: *mut c_void);
}
12 changes: 12 additions & 0 deletions artiq/runtime.rs/liblwip/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
authors = ["The ARTIQ Project Developers"]
name = "lwip"
version = "0.0.0"

[lib]
name = "lwip"
path = "lib.rs"

[dependencies]
lwip-sys = { path = "../liblwip-sys" }
std_artiq = { path = "../libstd_artiq" }
410 changes: 410 additions & 0 deletions artiq/runtime.rs/liblwip/lib.rs

Large diffs are not rendered by default.

10 changes: 9 additions & 1 deletion artiq/runtime.rs/libstd_artiq/lib.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
#![feature(lang_items, asm, collections, libc, needs_panic_runtime)]
#![feature(lang_items, asm, alloc, collections, libc, needs_panic_runtime)]
#![no_std]
#![needs_panic_runtime]

extern crate alloc_artiq;
extern crate alloc;
extern crate collections;
extern crate libc;

pub use core::{any, cell, clone, cmp, convert, default, hash, iter, marker, mem, num,
ops, option, ptr, result, sync,
char, i16, i32, i64, i8, isize, u16, u32, u64, u8, usize, f32, f64};
pub use alloc::{arc, rc, oom, raw_vec};
pub use collections::{binary_heap, borrow, boxed, btree_map, btree_set, fmt, linked_list, slice,
str, string, vec, vec_deque};

pub mod prelude {
pub mod v1 {
pub use core::prelude::v1::*;
20 changes: 10 additions & 10 deletions artiq/runtime.rs/src/scheduler.rs → artiq/runtime.rs/src/io.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
extern crate fringe;

use std::prelude::v1::*;
use std::vec::Vec;
use std::time::{Instant, Duration};
use self::fringe::OwnedStack;
use self::fringe::generator::{Generator, Yielder};

#[derive(Debug)]
pub struct WaitRequest {
struct WaitRequest {
timeout: Option<Instant>,
event: Option<WaitEvent>
}

#[derive(Debug)]
pub enum WaitResult {
enum WaitResult {
Completed,
TimedOut,
Interrupted
@@ -36,11 +36,11 @@ impl Scheduler {
Scheduler { threads: Vec::new(), index: 0 }
}

pub unsafe fn spawn<F: FnOnce(Io) + Send>(&mut self, stack_size: usize, f: F) {
pub unsafe fn spawn<F: FnOnce(Waiter) + Send>(&mut self, stack_size: usize, f: F) {
let stack = OwnedStack::new(stack_size);
let thread = Thread {
generator: Generator::unsafe_new(stack, move |yielder, _| {
f(Io(yielder))
f(Waiter(yielder))
}),
waiting_for: WaitRequest {
timeout: None,
@@ -102,21 +102,21 @@ impl Scheduler {
}

#[derive(Debug)]
pub enum WaitEvent {}
enum WaitEvent {}

impl WaitEvent {
fn completed(&self) -> bool {
match *self {}
}
}

pub type IoResult<T> = Result<T, ()>;
pub type Result<T> = ::std::result::Result<T, ()>;

#[derive(Debug)]
pub struct Io<'a>(&'a mut Yielder<WaitResult, WaitRequest, OwnedStack>);
pub struct Waiter<'a>(&'a mut Yielder<WaitResult, WaitRequest, OwnedStack>);

impl<'a> Io<'a> {
pub fn sleep(&mut self, duration: Duration) -> IoResult<()> {
impl<'a> Waiter<'a> {
pub fn sleep(&mut self, duration: Duration) -> Result<()> {
let request = WaitRequest {
timeout: Some(Instant::now() + duration),
event: None
61 changes: 41 additions & 20 deletions artiq/runtime.rs/src/lib.rs
Original file line number Diff line number Diff line change
@@ -2,29 +2,50 @@

#[macro_use]
extern crate std_artiq as std;
extern crate fringe;
extern crate lwip;

use std::prelude::v1::*;
use std::time::Duration;
use scheduler::Scheduler;

pub mod scheduler;
pub mod io;

extern {
fn network_init();
fn lwip_service();
}

fn test1(mut waiter: io::Waiter) {
loop {
println!("A");
waiter.sleep(std::time::Duration::from_millis(1000));
}
}

fn test2(mut waiter: io::Waiter) {
loop {
println!("B");
waiter.sleep(std::time::Duration::from_millis(500));
}
}

#[no_mangle]
pub extern "C" fn rust_main() {
// let mut scheduler = Scheduler::new();
// unsafe {
// scheduler.spawn(4096, move |mut io| {
// loop {
// println!("thread A");
// io.sleep(Duration::from_secs(1)).unwrap()
// }
// });
// scheduler.spawn(4096, move |mut io| {
// loop {
// println!("thread B");
// io.sleep(Duration::from_millis(333)).unwrap()
// }
// });
// }
// loop { scheduler.run() }
pub unsafe extern fn rust_main() {
println!("Accepting network sessions in Rust.");
network_init();

let addr = lwip::SocketAddr::new(lwip::IP4_ANY, 1234);
let mut listener = lwip::TcpListener::bind(addr).unwrap();
let mut stream = None;
loop {
lwip_service();
if let Some(new_stream) = listener.try_accept() {
stream = Some(new_stream)
}
if let Some(ref mut stream) = stream {
if let Some(pbuf) = stream.try_read().expect("read") {
println!("{:?}", pbuf.as_slice());
stream.write(pbuf.as_slice()).expect("write");
}
}
}
}
14 changes: 8 additions & 6 deletions artiq/runtime/main.c
Original file line number Diff line number Diff line change
@@ -51,7 +51,7 @@ static struct netif netif;
static ppp_pcb *ppp;
#endif

static void lwip_service(void)
void lwip_service(void)
{
sys_check_timeouts();
#ifdef CSR_ETHMAC_BASE
@@ -126,7 +126,7 @@ static void fsip_or_default(struct ip4_addr *d, char *key, int i1, int i2, int i
#endif
}

static void network_init(void)
void network_init(void)
{
struct ip4_addr local_ip;
struct ip4_addr netmask;
@@ -167,7 +167,7 @@ static void ppp_status_cb(ppp_pcb *pcb, int err_code, void *ctx)
}
}

static void network_init(void)
void network_init(void)
{
lwip_init();

@@ -264,6 +264,10 @@ extern void _fheap, _eheap;

extern void rust_main();

u16_t tcp_sndbuf_(struct tcp_pcb *pcb) {
return tcp_sndbuf(pcb);
}

int main(void)
{
irq_setmask(0);
@@ -278,14 +282,12 @@ int main(void)
puts("Press 't' to enter test mode...");
blink_led();

puts("Calling Rust...");
rust_main();

if(check_test_mode()) {
puts("Entering test mode.");
test_main();
} else {
puts("Entering regular mode.");
// rust_main();
session_startup_kernel();
regular_main();
}

0 comments on commit bf86305

Please sign in to comment.