Redo networking (#22)

* Rewriting network functions

* Add buffer to dup
Fix non-blocking handling by triggering once on enabling events to read to EOF

* Modifications for UDP API

* Implement TCP client side

* Add active close

* Add DMAR parser

* Implement basic TCP listening. Need to improve the state machine

* Reduce debugging

* Fixes for close procedure

* Updates to fix path processing in libstd
This commit is contained in:
Jeremy Soller 2016-10-26 13:19:56 -06:00 committed by GitHub
parent 268c859fd6
commit 2491e4771e
54 changed files with 1884 additions and 1476 deletions

View file

@ -42,7 +42,6 @@ clean:
cargo clean --manifest-path programs/userutils/Cargo.toml
cargo clean --manifest-path programs/smith/Cargo.toml
cargo clean --manifest-path programs/tar/Cargo.toml
cargo clean --manifest-path schemes/arpd/Cargo.toml
cargo clean --manifest-path schemes/ethernetd/Cargo.toml
cargo clean --manifest-path schemes/example/Cargo.toml
cargo clean --manifest-path schemes/ipd/Cargo.toml
@ -92,7 +91,6 @@ update:
cargo update --manifest-path programs/userutils/Cargo.toml
cargo update --manifest-path programs/smith/Cargo.toml
cargo update --manifest-path programs/tar/Cargo.toml
cargo update --manifest-path schemes/arpd/Cargo.toml
cargo update --manifest-path schemes/ethernetd/Cargo.toml
cargo update --manifest-path schemes/example/Cargo.toml
cargo update --manifest-path schemes/ipd/Cargo.toml
@ -120,7 +118,12 @@ $(KBUILD)/harddrive.bin: $(KBUILD)/kernel
qemu: $(KBUILD)/harddrive.bin
$(QEMU) $(QEMUFLAGS) -kernel $<
else
QEMUFLAGS+=-machine q35 -smp 4 -m 1024
QEMUFLAGS+=-smp 4 -m 1024
ifeq ($(iommu),no)
QEMUFLAGS+=-machine q35
else
QEMUFLAGS+=-machine q35,iommu=on
endif
ifeq ($(net),no)
QEMUFLAGS+=-net none
else
@ -406,7 +409,6 @@ userutils: \
filesystem/bin/sudo
schemes: \
filesystem/bin/arpd \
filesystem/bin/ethernetd \
filesystem/bin/example \
filesystem/bin/ipd \

View file

@ -0,0 +1,170 @@
use core::mem;
use super::sdt::Sdt;
/// The DMA Remapping Table
#[derive(Debug)]
pub struct Dmar {
sdt: &'static Sdt,
pub addr_width: u8,
pub flags: u8,
_rsv: [u8; 10],
}
impl Dmar {
pub fn new(sdt: &'static Sdt) -> Option<Dmar> {
if &sdt.signature == b"DMAR" && sdt.data_len() >= 12 { //Not valid if no local address and flags
let addr_width = unsafe { *(sdt.data_address() as *const u8) };
let flags = unsafe { *(sdt.data_address() as *const u8).offset(1) };
let rsv: [u8; 10] = unsafe { *((sdt.data_address() as *const u8).offset(2) as *const [u8; 10]) };
Some(Dmar {
sdt: sdt,
addr_width: addr_width,
flags: flags,
_rsv: rsv,
})
} else {
None
}
}
pub fn iter(&self) -> DmarIter {
DmarIter {
sdt: self.sdt,
i: 12 // Skip address width and flags
}
}
}
///
/// DMAR DMA Remapping Hardware Unit Definition
// TODO: Implement iterator on DmarDrhd scope
#[derive(Debug)]
#[repr(packed)]
pub struct DmarDrhd {
kind: u16,
length: u16,
flags: u8,
_rsv: u8,
segment: u16,
base: u64,
}
/// DMAR Reserved Memory Region Reporting
// TODO: Implement iterator on DmarRmrr scope
#[derive(Debug)]
#[repr(packed)]
pub struct DmarRmrr {
kind: u16,
length: u16,
_rsv: u16,
segment: u16,
base: u64,
limit: u64,
}
/// DMAR Root Port ATS Capability Reporting
// TODO: Implement iterator on DmarAtsr scope
#[derive(Debug)]
#[repr(packed)]
pub struct DmarAtsr {
kind: u16,
length: u16,
flags: u8,
_rsv: u8,
segment: u16,
}
/// DMAR Remapping Hardware Static Affinity
#[derive(Debug)]
#[repr(packed)]
pub struct DmarRhsa {
kind: u16,
length: u16,
_rsv: u32,
base: u64,
domain: u32,
}
/// DMAR ACPI Name-space Device Declaration
// TODO: Implement iterator on DmarAndd object name
#[derive(Debug)]
#[repr(packed)]
pub struct DmarAndd {
kind: u16,
length: u16,
_rsv: [u8; 3],
acpi_dev: u8,
}
/// DMAR Entries
#[derive(Debug)]
pub enum DmarEntry {
Drhd(&'static DmarDrhd),
InvalidDrhd(usize),
Rmrr(&'static DmarRmrr),
InvalidRmrr(usize),
Atsr(&'static DmarAtsr),
InvalidAtsr(usize),
Rhsa(&'static DmarRhsa),
InvalidRhsa(usize),
Andd(&'static DmarAndd),
InvalidAndd(usize),
Unknown(u16)
}
pub struct DmarIter {
sdt: &'static Sdt,
i: usize
}
impl Iterator for DmarIter {
type Item = DmarEntry;
fn next(&mut self) -> Option<Self::Item> {
if self.i + 4 <= self.sdt.data_len() {
let entry_type = unsafe { *((self.sdt.data_address() as *const u8).offset(self.i as isize) as *const u16) };
let entry_len = unsafe { *((self.sdt.data_address() as *const u8).offset(self.i as isize + 2) as *const u16) } as usize;
if self.i + entry_len <= self.sdt.data_len() {
let item = match entry_type {
0 => if entry_len >= mem::size_of::<DmarDrhd>() {
DmarEntry::Drhd(unsafe { &*((self.sdt.data_address() + self.i) as *const DmarDrhd) })
} else {
DmarEntry::InvalidDrhd(entry_len)
},
1 => if entry_len >= mem::size_of::<DmarRmrr>() {
DmarEntry::Rmrr(unsafe { &*((self.sdt.data_address() + self.i) as *const DmarRmrr) })
} else {
DmarEntry::InvalidRmrr(entry_len)
},
2 => if entry_len >= mem::size_of::<DmarAtsr>() {
DmarEntry::Atsr(unsafe { &*((self.sdt.data_address() + self.i) as *const DmarAtsr) })
} else {
DmarEntry::InvalidAtsr(entry_len)
},
3 => if entry_len == mem::size_of::<DmarRhsa>() {
DmarEntry::Rhsa(unsafe { &*((self.sdt.data_address() + self.i) as *const DmarRhsa) })
} else {
DmarEntry::InvalidRhsa(entry_len)
},
4 => if entry_len >= mem::size_of::<DmarAndd>() {
DmarEntry::Andd(unsafe { &*((self.sdt.data_address() + self.i) as *const DmarAndd) })
} else {
DmarEntry::InvalidAndd(entry_len)
},
_ => DmarEntry::Unknown(entry_type)
};
self.i += entry_len;
Some(item)
} else {
None
}
} else {
None
}
}
}

View file

@ -9,12 +9,14 @@ use memory::{allocate_frames, Frame};
use paging::{entry, ActivePageTable, Page, PhysicalAddress, VirtualAddress};
use start::{kstart_ap, CPU_COUNT, AP_READY};
use self::dmar::Dmar;
use self::local_apic::LocalApic;
use self::madt::{Madt, MadtEntry};
use self::rsdt::Rsdt;
use self::sdt::Sdt;
use self::xsdt::Xsdt;
pub mod dmar;
pub mod local_apic;
pub mod madt;
pub mod rsdt;
@ -133,6 +135,12 @@ pub fn init_sdt(sdt: &'static Sdt, active_table: &mut ActivePageTable) {
// Unmap trampoline
active_table.unmap(trampoline_page);
active_table.flush(trampoline_page);
} else if let Some(dmar) = Dmar::new(sdt) {
println!(": {}: {}", dmar.addr_width, dmar.flags);
for dmar_entry in dmar.iter() {
println!(" {:?}", dmar_entry);
}
} else {
println!(": Unknown");
}

View file

@ -38,13 +38,43 @@ impl<R> EventQueue<R> {
Ok(())
}
/// Remove a file from the event queue, returning its callback if found
pub fn remove(&mut self, fd: RawFd) -> Result<Option<Box<FnMut(usize) -> Result<Option<R>>>>> {
if let Some(callback) = self.callbacks.remove(&fd) {
syscall::fevent(fd, 0).map_err(|x| Error::from_sys(x))?;
Ok(Some(callback))
} else {
Ok(None)
}
}
/// Send an event to a descriptor callback
pub fn trigger(&mut self, fd: RawFd, count: usize) -> Result<Option<R>> {
if let Some(callback) = self.callbacks.get_mut(&fd) {
callback(count)
} else {
Ok(None)
}
}
/// Send an event to all descriptor callbacks, useful for cleaning out buffers after init
pub fn trigger_all(&mut self, count: usize) -> Result<Vec<R>> {
let mut rets = Vec::new();
for (_fd, callback) in self.callbacks.iter_mut() {
if let Some(ret) = callback(count)? {
rets.push(ret);
}
}
Ok(rets)
}
/// Process the event queue until a callback returns Some(R)
pub fn run(&mut self) -> Result<R> {
loop {
let mut event = syscall::Event::default();
self.file.read(&mut event)?;
if let Some(callback) = self.callbacks.get_mut(&event.id) {
if let Some(ret) = callback(event.data)? {
if self.file.read(&mut event)? > 0 {
if let Some(ret) = self.trigger(event.id, event.data)? {
return Ok(ret);
}
}

View file

@ -4,7 +4,7 @@ use syscall::error::*;
pub trait Resource {
/// Duplicate the resource
/// Returns `EPERM` if the operation is not supported.
fn dup(&self) -> Result<Box<Self>> {
fn dup(&self, _buf: &[u8]) -> Result<Box<Self>> {
Err(Error::new(EPERM))
}

View file

@ -16,7 +16,7 @@ pub trait ResourceScheme<T: Resource> {
SYS_RMDIR => self.rmdir(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }, packet.uid, packet.gid),
SYS_UNLINK => self.unlink(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }, packet.uid, packet.gid),
SYS_DUP => self.dup(packet.b),
SYS_DUP => self.dup(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }),
SYS_READ => self.read(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }),
SYS_WRITE => self.write(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }),
SYS_LSEEK => self.seek(packet.b, packet.c, packet.d),
@ -54,9 +54,9 @@ pub trait ResourceScheme<T: Resource> {
}
/* Resource operations */
fn dup(&self, old_id: usize) -> Result<usize> {
fn dup(&self, old_id: usize, buf: &[u8]) -> Result<usize> {
let old = unsafe { &*(old_id as *const T) };
let resource = old.dup()?;
let resource = old.dup(buf)?;
let resource_ptr = Box::into_raw(resource);
Ok(resource_ptr as usize)
}

View file

@ -52,10 +52,14 @@ fn main() {
let mut event = Event::default();
event_file.read(&mut event).expect("ahcid: failed to read event file");
if event.id == socket_fd {
let mut packet = Packet::default();
socket.read(&mut packet).expect("ahcid: failed to read disk scheme");
scheme.handle(&mut packet);
socket.write(&mut packet).expect("ahcid: failed to write disk scheme");
loop {
let mut packet = Packet::default();
if socket.read(&mut packet).expect("ahcid: failed to read disk scheme") == 0 {
break;
}
scheme.handle(&mut packet);
socket.write(&mut packet).expect("ahcid: failed to write disk scheme");
}
} else if event.id == irq_fd {
let mut irq = [0; 8];
if irq_file.read(&mut irq).expect("ahcid: failed to read irq file") >= irq.len() {

View file

@ -47,7 +47,7 @@ impl Scheme for DiskScheme {
}
}
fn dup(&self, id: usize) -> Result<usize> {
fn dup(&self, id: usize, _buf: &[u8]) -> Result<usize> {
let mut handles = self.handles.lock();
let new_handle = {
let handle = handles.get(&id).ok_or(Error::new(EBADF))?;

View file

@ -109,7 +109,7 @@ impl Scheme for Intel8254x {
}
}
fn dup(&self, id: usize) -> Result<usize> {
fn dup(&self, id: usize, _buf: &[u8]) -> Result<usize> {
Ok(id)
}

View file

@ -80,16 +80,20 @@ fn main() {
let socket_packet = socket.clone();
event_queue.add(socket_fd, move |_count: usize| -> Result<Option<usize>> {
let mut packet = Packet::default();
socket_packet.borrow_mut().read(&mut packet)?;
loop {
let mut packet = Packet::default();
if socket_packet.borrow_mut().read(&mut packet)? == 0 {
break;
}
let a = packet.a;
device.handle(&mut packet);
if packet.a == (-EWOULDBLOCK) as usize {
packet.a = a;
todo.borrow_mut().push(packet);
} else {
socket_packet.borrow_mut().write(&mut packet)?;
let a = packet.a;
device.handle(&mut packet);
if packet.a == (-EWOULDBLOCK) as usize {
packet.a = a;
todo.borrow_mut().push(packet);
} else {
socket_packet.borrow_mut().write(&mut packet)?;
}
}
let next_read = device.next_read();
@ -100,10 +104,8 @@ fn main() {
Ok(None)
}).expect("e1000d: failed to catch events on IRQ file");
loop {
let event_count = event_queue.run().expect("e1000d: failed to handle events");
let event_packet = Packet {
for event_count in event_queue.trigger_all(0).expect("e1000d: failed to trigger events") {
socket.borrow_mut().write(&Packet {
id: 0,
pid: 0,
uid: 0,
@ -112,9 +114,22 @@ fn main() {
b: 0,
c: syscall::flag::EVENT_READ,
d: event_count
};
}).expect("e1000d: failed to write event");
}
socket.borrow_mut().write(&event_packet).expect("vesad: failed to write display event");
loop {
let event_count = event_queue.run().expect("e1000d: failed to handle events");
socket.borrow_mut().write(&Packet {
id: 0,
pid: 0,
uid: 0,
gid: 0,
a: syscall::number::SYS_FEVENT,
b: 0,
c: syscall::flag::EVENT_READ,
d: event_count
}).expect("e1000d: failed to write event");
}
}
unsafe { let _ = syscall::physunmap(address); }

View file

@ -32,6 +32,92 @@ bitflags! {
}
}
struct Ps2d {
input: File,
lshift: bool,
rshift: bool,
packets: [u8; 4],
packet_i: usize,
extra_packet: bool
}
impl Ps2d {
fn new(input: File, extra_packet: bool) -> Self {
Ps2d {
input: input,
lshift: false,
rshift: false,
packets: [0; 4],
packet_i: 0,
extra_packet: extra_packet
}
}
fn handle(&mut self, keyboard: bool, data: u8) {
if keyboard {
let (scancode, pressed) = if data >= 0x80 {
(data - 0x80, false)
} else {
(data, true)
};
if scancode == 0x2A {
self.lshift = pressed;
} else if scancode == 0x36 {
self.rshift = pressed;
}
self.input.write(&KeyEvent {
character: keymap::get_char(scancode, self.lshift || self.rshift),
scancode: scancode,
pressed: pressed
}.to_event()).expect("ps2d: failed to write key event");
} else {
self.packets[self.packet_i] = data;
self.packet_i += 1;
let flags = MousePacketFlags::from_bits_truncate(self.packets[0]);
if ! flags.contains(ALWAYS_ON) {
println!("MOUSE MISALIGN {:X}", self.packets[0]);
self.packets = [0; 4];
self.packet_i = 0;
} else if self.packet_i >= self.packets.len() || (!self.extra_packet && self.packet_i >= 3) {
if ! flags.contains(X_OVERFLOW) && ! flags.contains(Y_OVERFLOW) {
let mut dx = self.packets[1] as i32;
if flags.contains(X_SIGN) {
dx -= 0x100;
}
let mut dy = -(self.packets[2] as i32);
if flags.contains(Y_SIGN) {
dy += 0x100;
}
let _extra = if self.extra_packet {
self.packets[3]
} else {
0
};
self.input.write(&MouseEvent {
x: dx,
y: dy,
left_button: flags.contains(LEFT_BUTTON),
middle_button: flags.contains(MIDDLE_BUTTON),
right_button: flags.contains(RIGHT_BUTTON)
}.to_event()).expect("ps2d: failed to write mouse event");
} else {
println!("ps2d: overflow {:X} {:X} {:X} {:X}", self.packets[0], self.packets[1], self.packets[2], self.packets[3]);
}
self.packets = [0; 4];
self.packet_i = 0;
}
}
}
}
fn main() {
thread::spawn(|| {
unsafe {
@ -39,9 +125,11 @@ fn main() {
asm!("cli" :::: "intel", "volatile");
}
let input = File::open("display:input").expect("ps2d: failed to open display:input");
let extra_packet = controller::Ps2::new().init();
let mut input = File::open("display:input").expect("ps2d: failed to open display:input");
let mut ps2d = Ps2d::new(input, extra_packet);
let mut event_queue = EventQueue::<(bool, u8)>::new().expect("ps2d: failed to create event queue");
@ -81,75 +169,13 @@ fn main() {
}
}).expect("ps2d: failed to poll irq:12");
let mut lshift = false;
let mut rshift = false;
let mut packets = [0; 4];
let mut packet_i = 0;
for (keyboard, data) in event_queue.trigger_all(0).expect("ps2d: failed to trigger events") {
ps2d.handle(keyboard, data);
}
loop {
let (keyboard, data) = event_queue.run().expect("ps2d: failed to handle events");
if keyboard {
let (scancode, pressed) = if data >= 0x80 {
(data - 0x80, false)
} else {
(data, true)
};
if scancode == 0x2A {
lshift = pressed;
} else if scancode == 0x36 {
rshift = pressed;
}
input.write(&KeyEvent {
character: keymap::get_char(scancode, lshift || rshift),
scancode: scancode,
pressed: pressed
}.to_event()).expect("ps2d: failed to write key event");
} else {
packets[packet_i] = data;
packet_i += 1;
let flags = MousePacketFlags::from_bits_truncate(packets[0]);
if ! flags.contains(ALWAYS_ON) {
println!("MOUSE MISALIGN {:X}", packets[0]);
packets = [0; 4];
packet_i = 0;
} else if packet_i >= packets.len() || (!extra_packet && packet_i >= 3) {
if ! flags.contains(X_OVERFLOW) && ! flags.contains(Y_OVERFLOW) {
let mut dx = packets[1] as i32;
if flags.contains(X_SIGN) {
dx -= 0x100;
}
let mut dy = -(packets[2] as i32);
if flags.contains(Y_SIGN) {
dy += 0x100;
}
let _extra = if extra_packet {
packets[3]
} else {
0
};
input.write(&MouseEvent {
x: dx,
y: dy,
left_button: flags.contains(LEFT_BUTTON),
middle_button: flags.contains(MIDDLE_BUTTON),
right_button: flags.contains(RIGHT_BUTTON)
}.to_event()).expect("ps2d: failed to write mouse event");
} else {
println!("ps2d: overflow {:X} {:X} {:X} {:X}", packets[0], packets[1], packets[2], packets[3]);
}
packets = [0; 4];
packet_i = 0;
}
}
ps2d.handle(keyboard, data);
}
});
}

View file

@ -84,7 +84,7 @@ impl SchemeMut for Rtl8168 {
}
}
fn dup(&mut self, id: usize) -> Result<usize> {
fn dup(&mut self, id: usize, _buf: &[u8]) -> Result<usize> {
Ok(id)
}

View file

@ -85,16 +85,20 @@ fn main() {
let socket_fd = socket.borrow().as_raw_fd();
let socket_packet = socket.clone();
event_queue.add(socket_fd, move |_count: usize| -> Result<Option<usize>> {
let mut packet = Packet::default();
socket_packet.borrow_mut().read(&mut packet)?;
loop {
let mut packet = Packet::default();
if socket_packet.borrow_mut().read(&mut packet)? == 0 {
break;
}
let a = packet.a;
device.borrow_mut().handle(&mut packet);
if packet.a == (-EWOULDBLOCK) as usize {
packet.a = a;
todo.borrow_mut().push(packet);
} else {
socket_packet.borrow_mut().write(&mut packet)?;
let a = packet.a;
device.borrow_mut().handle(&mut packet);
if packet.a == (-EWOULDBLOCK) as usize {
packet.a = a;
todo.borrow_mut().push(packet);
} else {
socket_packet.borrow_mut().write(&mut packet)?;
}
}
let next_read = device.borrow().next_read();
@ -105,10 +109,8 @@ fn main() {
Ok(None)
}).expect("rtl8168d: failed to catch events on IRQ file");
loop {
let event_count = event_queue.run().expect("rtl8168d: failed to handle events");
let event_packet = Packet {
for event_count in event_queue.trigger_all(0).expect("rtl8168d: failed to trigger events") {
socket.borrow_mut().write(&Packet {
id: 0,
pid: 0,
uid: 0,
@ -117,9 +119,22 @@ fn main() {
b: 0,
c: syscall::flag::EVENT_READ,
d: event_count
};
}).expect("rtl8168d: failed to write event");
}
socket.borrow_mut().write(&event_packet).expect("vesad: failed to write display event");
loop {
let event_count = event_queue.run().expect("rtl8168d: failed to handle events");
socket.borrow_mut().write(&Packet {
id: 0,
pid: 0,
uid: 0,
gid: 0,
a: syscall::number::SYS_FEVENT,
b: 0,
c: syscall::flag::EVENT_READ,
d: event_count
}).expect("rtl8168d: failed to write event");
}
}
unsafe { let _ = syscall::physunmap(address); }

View file

@ -63,7 +63,6 @@ fn main() {
loop {
let mut packet = Packet::default();
socket.read(&mut packet).expect("vesad: failed to read display scheme");
//println!("vesad: {:?}", packet);
// If it is a read packet, and there is no data, block it. Otherwise, handle packet
if packet.a == syscall::number::SYS_READ && packet.d > 0 && scheme.will_block(packet.b) {

View file

@ -60,7 +60,7 @@ impl SchemeMut for DisplayScheme {
}
}
fn dup(&mut self, id: usize) -> Result<usize> {
fn dup(&mut self, id: usize, _buf: &[u8]) -> Result<usize> {
Ok(id)
}

View file

@ -1,7 +1,6 @@
randd
initfs:bin/pcid /etc/pcid.toml
ethernetd
arpd
ipd
tcpd
udpd

View file

@ -33,7 +33,7 @@ impl Scheme for DebugScheme {
Ok(0)
}
fn dup(&self, _file: usize) -> Result<usize> {
fn dup(&self, _file: usize, _buf: &[u8]) -> Result<usize> {
Ok(0)
}

View file

@ -88,7 +88,7 @@ impl Scheme for EnvScheme {
}
}
fn dup(&self, id: usize) -> Result<usize> {
fn dup(&self, id: usize, _buf: &[u8]) -> Result<usize> {
let new_handle = {
let handles = self.handles.read();
let handle = handles.get(&id).ok_or(Error::new(EBADF))?;

View file

@ -39,7 +39,7 @@ impl Scheme for EventScheme {
Ok(id)
}
fn dup(&self, id: usize) -> Result<usize> {
fn dup(&self, id: usize, _buf: &[u8]) -> Result<usize> {
let handle = {
let handles = self.handles.read();
let handle_weak = handles.get(&id).ok_or(Error::new(EBADF))?;

View file

@ -57,7 +57,7 @@ impl Scheme for InitFsScheme {
Err(Error::new(ENOENT))
}
fn dup(&self, id: usize) -> Result<usize> {
fn dup(&self, id: usize, _buf: &[u8]) -> Result<usize> {
let (path, data, mode, seek) = {
let handles = self.handles.read();
let handle = handles.get(&id).ok_or(Error::new(EBADF))?;

View file

@ -40,7 +40,7 @@ impl Scheme for IrqScheme {
}
}
fn dup(&self, file: usize) -> Result<usize> {
fn dup(&self, file: usize, _buf: &[u8]) -> Result<usize> {
Ok(file)
}

View file

@ -42,7 +42,7 @@ pub fn pipe(flags: usize) -> (usize, usize) {
pub struct PipeScheme;
impl Scheme for PipeScheme {
fn dup(&self, id: usize) -> Result<usize> {
fn dup(&self, id: usize, _buf: &[u8]) -> Result<usize> {
let mut pipes = pipes_mut();
let read_option = pipes.0.get(&id).map(|pipe| pipe.clone());

View file

@ -56,7 +56,7 @@ impl Scheme for RootScheme {
}
}
fn dup(&self, file: usize) -> Result<usize> {
fn dup(&self, file: usize, _buf: &[u8]) -> Result<usize> {
let mut handles = self.handles.write();
let inner = {
let inner = handles.get(&file).ok_or(Error::new(EBADF))?;
@ -89,12 +89,24 @@ impl Scheme for RootScheme {
inner.write(buf)
}
fn fevent(&self, file: usize, _flags: usize) -> Result<usize> {
Ok(file)
fn fevent(&self, file: usize, flags: usize) -> Result<usize> {
let inner = {
let handles = self.handles.read();
let inner = handles.get(&file).ok_or(Error::new(EBADF))?;
inner.clone()
};
inner.fevent(flags)
}
fn fsync(&self, _file: usize) -> Result<usize> {
Ok(0)
fn fsync(&self, file: usize) -> Result<usize> {
let inner = {
let handles = self.handles.read();
let inner = handles.get(&file).ok_or(Error::new(EBADF))?;
inner.clone()
};
inner.fsync()
}
fn close(&self, file: usize) -> Result<usize> {

View file

@ -92,7 +92,7 @@ impl Scheme for SysScheme {
Err(Error::new(ENOENT))
}
fn dup(&self, id: usize) -> Result<usize> {
fn dup(&self, id: usize, _buf: &[u8]) -> Result<usize> {
let (path, data, mode, seek) = {
let handles = self.handles.read();
let handle = handles.get(&id).ok_or(Error::new(EBADF))?;

View file

@ -61,10 +61,7 @@ impl UserInner {
};
let len = self.todo.send(packet);
//TODO: Use O_NONBLOCK and send one notification
for _i in 0 .. len {
context::event::trigger(ROOT_SCHEME_ID.load(Ordering::SeqCst), self.handle_id, EVENT_READ, mem::size_of::<Packet>());
}
context::event::trigger(ROOT_SCHEME_ID.load(Ordering::SeqCst), self.handle_id, EVENT_READ, mem::size_of::<Packet>() * len);
Error::demux(self.done.receive(&id))
}
@ -182,6 +179,14 @@ impl UserInner {
Ok(i * packet_size)
}
pub fn fevent(&self, _flags: usize) -> Result<usize> {
Ok(self.handle_id)
}
pub fn fsync(&self) -> Result<usize> {
Ok(0)
}
}
/// UserInner has to be wrapped
@ -230,9 +235,12 @@ impl Scheme for UserScheme {
result
}
fn dup(&self, file: usize) -> Result<usize> {
fn dup(&self, file: usize, buf: &[u8]) -> Result<usize> {
let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?;
inner.call(SYS_DUP, file, 0, 0)
let address = inner.capture(buf)?;
let result = inner.call(SYS_DUP, file, address, buf.len());
let _ = inner.release(address);
result
}
fn read(&self, file: usize, buf: &mut [u8]) -> Result<usize> {

View file

@ -83,10 +83,10 @@ pub fn open(path: &[u8], flags: usize) -> Result<usize> {
let reference_opt = parts.next();
let (scheme_id, file_id) = {
let namespace = namespace_opt.ok_or(Error::new(ENOENT))?;
let namespace = namespace_opt.ok_or(Error::new(ENODEV))?;
let (scheme_id, scheme) = {
let schemes = scheme::schemes();
let (scheme_id, scheme) = schemes.get_name(namespace).ok_or(Error::new(ENOENT))?;
let (scheme_id, scheme) = schemes.get_name(namespace).ok_or(Error::new(ENODEV))?;
(scheme_id, scheme.clone())
};
let file_id = scheme.open(reference_opt.unwrap_or(b""), flags, uid, gid)?;
@ -146,10 +146,10 @@ pub fn mkdir(path: &[u8], mode: u16) -> Result<usize> {
let namespace_opt = parts.next();
let reference_opt = parts.next();
let namespace = namespace_opt.ok_or(Error::new(ENOENT))?;
let namespace = namespace_opt.ok_or(Error::new(ENODEV))?;
let scheme = {
let schemes = scheme::schemes();
let (_scheme_id, scheme) = schemes.get_name(namespace).ok_or(Error::new(ENOENT))?;
let (_scheme_id, scheme) = schemes.get_name(namespace).ok_or(Error::new(ENODEV))?;
scheme.clone()
};
scheme.mkdir(reference_opt.unwrap_or(b""), mode, uid, gid)
@ -168,10 +168,10 @@ pub fn rmdir(path: &[u8]) -> Result<usize> {
let namespace_opt = parts.next();
let reference_opt = parts.next();
let namespace = namespace_opt.ok_or(Error::new(ENOENT))?;
let namespace = namespace_opt.ok_or(Error::new(ENODEV))?;
let scheme = {
let schemes = scheme::schemes();
let (_scheme_id, scheme) = schemes.get_name(namespace).ok_or(Error::new(ENOENT))?;
let (_scheme_id, scheme) = schemes.get_name(namespace).ok_or(Error::new(ENODEV))?;
scheme.clone()
};
scheme.rmdir(reference_opt.unwrap_or(b""), uid, gid)
@ -190,10 +190,10 @@ pub fn unlink(path: &[u8]) -> Result<usize> {
let namespace_opt = parts.next();
let reference_opt = parts.next();
let namespace = namespace_opt.ok_or(Error::new(ENOENT))?;
let namespace = namespace_opt.ok_or(Error::new(ENODEV))?;
let scheme = {
let schemes = scheme::schemes();
let (_scheme_id, scheme) = schemes.get_name(namespace).ok_or(Error::new(ENOENT))?;
let (_scheme_id, scheme) = schemes.get_name(namespace).ok_or(Error::new(ENODEV))?;
scheme.clone()
};
scheme.unlink(reference_opt.unwrap_or(b""), uid, gid)
@ -222,7 +222,7 @@ pub fn close(fd: usize) -> Result<usize> {
}
/// Duplicate file descriptor
pub fn dup(fd: usize) -> Result<usize> {
pub fn dup(fd: usize, buf: &[u8]) -> Result<usize> {
let file = {
let contexts = context::contexts();
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
@ -237,7 +237,7 @@ pub fn dup(fd: usize) -> Result<usize> {
let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?;
scheme.clone()
};
scheme.dup(file.number)?
scheme.dup(file.number, buf)?
};
let contexts = context::contexts();

View file

@ -39,7 +39,7 @@ pub extern fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize
SYS_ARG_MSLICE => file_op_mut_slice(a, b, validate_slice_mut(c as *mut u8, d)?),
_ => match a {
SYS_CLOSE => close(b),
SYS_DUP => dup(b),
SYS_DUP => dup(b, validate_slice(c as *const u8, d)?),
SYS_FEVENT => fevent(b, c),
_ => file_op(a, b, c, d)
}

View file

@ -227,7 +227,7 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<usize> {
let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?;
scheme.clone()
};
let result = scheme.dup(file.number);
let result = scheme.dup(file.number, &[]);
result
};
match result {

2
libstd

@ -1 +1 @@
Subproject commit 4f642eed87af22913af7bef9c71910ee1765445e
Subproject commit a390903a03d7cebe448af803e635a46fa1609262

@ -1 +1 @@
Subproject commit 9faaf3a9690186a12da980fb877c8f05faea62aa
Subproject commit 1afcf7ab26ca3f697082674e6a72c94dd211c74b

@ -1 +1 @@
Subproject commit 4eae543a60a5d6b0298db09bc48b2e6fab60b021
Subproject commit 6926b235c47488f1bb2f5574a0445c7698e3ab99

@ -1 +1 @@
Subproject commit 517ca6d125e90d6b30e45a759f54b1d1b3b346d4
Subproject commit 78cd23bf67adad79fb3e45ae4647055b01df026f

View file

@ -1,7 +0,0 @@
[package]
name = "arpd"
version = "0.1.0"
[dependencies]
netutils = { path = "../../programs/netutils/" }
syscall = { path = "../../syscall/" }

View file

@ -1,40 +0,0 @@
extern crate netutils;
extern crate syscall;
use netutils::{getcfg, Ipv4Addr, MacAddr, Arp};
use std::thread;
fn main() {
thread::spawn(move || {
while let Ok(link) = syscall::open("ethernet:/806", syscall::O_RDWR) {
loop {
let mut bytes = [0; 65536];
if let Ok(count) = syscall::read(link, &mut bytes) {
if let Some(packet) = Arp::from_bytes(&bytes[..count]) {
let mac_addr = MacAddr::from_str(&getcfg("mac").expect("arpd: failed to get mac address"));
let ip_addr = Ipv4Addr::from_str(&getcfg("ip").expect("arpd: failed to get ip address"));
if packet.header.oper.get() == 1 && packet.header.dst_ip.equals(ip_addr) {
let mut response = Arp {
header: packet.header,
data: packet.data.clone(),
};
response.header.oper.set(2);
response.header.dst_mac = packet.header.src_mac;
response.header.dst_ip = packet.header.src_ip;
response.header.src_mac = mac_addr;
response.header.src_ip = ip_addr;
let _ = syscall::write(link, &response.to_bytes());
}
}
} else {
break;
}
}
let _ = syscall::close(link);
}
panic!("ARP: Failed to open ethernet");
});
}

View file

@ -68,21 +68,27 @@ fn main() {
}).expect("ethernetd: failed to listen for network events");
event_queue.add(socket_fd, move |_count: usize| -> Result<Option<()>> {
let mut packet = Packet::default();
socket.borrow_mut().read(&mut packet)?;
loop {
let mut packet = Packet::default();
if socket.borrow_mut().read(&mut packet)? == 0 {
break;
}
let a = packet.a;
scheme.borrow_mut().handle(&mut packet);
if packet.a == (-EWOULDBLOCK) as usize {
packet.a = a;
todo.borrow_mut().push(packet);
} else {
socket.borrow_mut().write(&mut packet)?;
let a = packet.a;
scheme.borrow_mut().handle(&mut packet);
if packet.a == (-EWOULDBLOCK) as usize {
packet.a = a;
todo.borrow_mut().push(packet);
} else {
socket.borrow_mut().write(&mut packet)?;
}
}
Ok(None)
}).expect("ethernetd: failed to listen for scheme events");
event_queue.trigger_all(0).expect("ethernetd: failed to trigger events");
event_queue.run().expect("ethernetd: failed to run event loop");
});
}

View file

@ -1,20 +1,21 @@
use std::collections::{BTreeMap, VecDeque};
use std::fs::File;
use std::io::{self, Read};
use std::io::{self, Read, Write};
use std::os::unix::io::AsRawFd;
use std::{cmp, str, u16};
use netutils::{getcfg, n16, MacAddr, EthernetII, EthernetIIHeader};
use netutils::{getcfg, MacAddr, EthernetII};
use syscall;
use syscall::error::{Error, Result, EACCES, EBADF, ENOENT, EINVAL, EWOULDBLOCK};
use syscall::error::{Error, Result, EACCES, EBADF, EINVAL, EWOULDBLOCK};
use syscall::flag::O_NONBLOCK;
use syscall::scheme::SchemeMut;
#[derive(Clone)]
pub struct Handle {
/// The flags this handle was opened with
flags: usize,
/// The Host's MAC address
pub host_addr: MacAddr,
/// The Peer's MAC address
pub peer_addr: Option<MacAddr>,
/// The ethernet type
pub ethertype: u16,
/// The data
@ -39,65 +40,51 @@ impl EthernetScheme {
//TODO: Minimize allocation
//TODO: Reduce iteration cost (use BTreeMap of ethertype to handle?)
pub fn input(&mut self) -> io::Result<usize> {
let mut bytes = [0; 65536];
let count = self.network.read(&mut bytes)?;
if let Some(frame) = EthernetII::from_bytes(&bytes[.. count]) {
for (_id, handle) in self.handles.iter_mut() {
if frame.header.ethertype.get() == handle.ethertype {
if handle.peer_addr.is_none() {
handle.peer_addr = Some(frame.header.src);
}
handle.frames.push_back(frame.clone());
}
let mut total = 0;
loop {
let mut bytes = [0; 65536];
let count = self.network.read(&mut bytes)?;
if count == 0 {
break;
}
if let Some(frame) = EthernetII::from_bytes(&bytes[.. count]) {
for (_id, handle) in self.handles.iter_mut() {
if frame.header.ethertype.get() == handle.ethertype {
handle.frames.push_back(frame.clone());
}
}
total += count;
}
Ok(count)
} else {
Ok(0)
}
Ok(total)
}
}
impl SchemeMut for EthernetScheme {
fn open(&mut self, url: &[u8], _flags: usize, uid: u32, _gid: u32) -> Result<usize> {
fn open(&mut self, url: &[u8], flags: usize, uid: u32, _gid: u32) -> Result<usize> {
if uid == 0 {
let mac_addr = MacAddr::from_str(&getcfg("mac").map_err(|err| err.into_sys())?);
let path = try!(str::from_utf8(url).or(Err(Error::new(EINVAL))));
let mut parts = path.split("/");
if let Some(host_string) = parts.next() {
if let Some(ethertype_string) = parts.next() {
let ethertype = u16::from_str_radix(ethertype_string, 16).unwrap_or(0);
let peer_addr = if ! host_string.is_empty() {
Some(MacAddr::from_str(host_string))
} else {
None
};
let ethertype = u16::from_str_radix(path, 16).unwrap_or(0);
let next_id = self.next_id;
self.next_id += 1;
let next_id = self.next_id;
self.next_id += 1;
self.handles.insert(next_id, Handle {
host_addr: mac_addr,
peer_addr: peer_addr,
ethertype: ethertype,
frames: VecDeque::new()
});
self.handles.insert(next_id, Handle {
flags: flags,
host_addr: mac_addr,
ethertype: ethertype,
frames: VecDeque::new()
});
return Ok(next_id);
} else {
println!("Ethernet: No ethertype provided");
}
} else {
println!("Ethernet: No host provided");
}
Err(Error::new(ENOENT))
Ok(next_id)
} else {
Err(Error::new(EACCES))
}
}
fn dup(&mut self, id: usize) -> Result<usize> {
fn dup(&mut self, id: usize, _buf: &[u8]) -> Result<usize> {
let next_id = self.next_id;
self.next_id += 1;
@ -115,11 +102,14 @@ impl SchemeMut for EthernetScheme {
let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?;
if let Some(frame) = handle.frames.pop_front() {
for (b, d) in buf.iter_mut().zip(frame.data.iter()) {
let data = frame.to_bytes();
for (b, d) in buf.iter_mut().zip(data.iter()) {
*b = *d;
}
Ok(cmp::min(buf.len(), frame.data.len()))
Ok(cmp::min(buf.len(), data.len()))
} else if handle.flags & O_NONBLOCK == O_NONBLOCK {
Ok(0)
} else {
Err(Error::new(EWOULDBLOCK))
}
@ -128,17 +118,12 @@ impl SchemeMut for EthernetScheme {
fn write(&mut self, id: usize, buf: &[u8]) -> Result<usize> {
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
match syscall::write(self.network.as_raw_fd(), &EthernetII {
header: EthernetIIHeader {
src: handle.host_addr,
dst: handle.peer_addr.unwrap_or(MacAddr::BROADCAST),
ethertype: n16::new(handle.ethertype),
},
data: Vec::from(buf),
}
.to_bytes()) {
Ok(_) => Ok(buf.len()),
Err(err) => Err(err),
if let Some(mut frame) = EthernetII::from_bytes(buf) {
frame.header.src = handle.host_addr;
frame.header.ethertype.set(handle.ethertype);
self.network.write(&frame.to_bytes()).map_err(|err| err.into_sys())
} else {
Err(Error::new(EINVAL))
}
}
@ -151,14 +136,16 @@ impl SchemeMut for EthernetScheme {
fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result<usize> {
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
let path_string = format!("ethernet:{}/{:X}", handle.peer_addr.map_or(String::new(), |mac| mac.to_string()), handle.ethertype);
let path_string = format!("ethernet:{:X}", handle.ethertype);
let path = path_string.as_bytes();
for (b, p) in buf.iter_mut().zip(path.iter()) {
*b = *p;
let mut i = 0;
while i < buf.len() && i < path.len() {
buf[i] = path[i];
i += 1;
}
Ok(cmp::min(buf.len(), path.len()))
Ok(i)
}
fn fsync(&mut self, id: usize) -> Result<usize> {
@ -169,7 +156,9 @@ impl SchemeMut for EthernetScheme {
fn close(&mut self, id: usize) -> Result<usize> {
let handle = self.handles.remove(&id).ok_or(Error::new(EBADF))?;
drop(handle);
Ok(0)
}
}

View file

@ -15,7 +15,7 @@ impl Scheme for ExampleScheme {
Ok(0)
}
fn dup(&self, file: usize) -> Result<usize> {
fn dup(&self, file: usize, _buf: &[u8]) -> Result<usize> {
Ok(file)
}

View file

@ -3,6 +3,6 @@ name = "ipd"
version = "0.1.0"
[dependencies]
event = { path = "../../crates/event/" }
netutils = { path = "../../programs/netutils/" }
resource_scheme = { path = "../../crates/resource_scheme/" }
syscall = { path = "../../syscall/" }

View file

@ -1,120 +1,371 @@
#![feature(rand)]
//! Implementation of the IP Scheme as a userland driver.
//!
//! # Role
//!
//! See https://en.wikipedia.org/wiki/Internet_Protocol for more details about the
//! IP protocol. Clients will often prefer using either higher-level protocols TCP
//! or UDP, both of which are built upon IP.
//!
//! # URL Syntax
//!
//! To open a IP connection, use `ip:[host]/protocol`.
//!
//! * If `host` is specified, it must be an ipv4 number (e.g. `192.168.0.1`)
//! and the connection may be used immediately to send/receive data. Ip v4 number
//! `127.0.0.1` is hardwired to the loopback device (i.e. localhost), which doesn't
//! access any physical device and in which data can only be read by the same
//! connection that has written it.
//! * If `host` is omitted, this connectino will wait for a distant peer to
//! connect.
//! * The `protocol` is the hex-based number of the ip protocol
//! (see http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml).
extern crate event;
extern crate netutils;
extern crate resource_scheme;
extern crate syscall;
use event::EventQueue;
use netutils::{getcfg, n16, Ipv4Addr, MacAddr, Ipv4, EthernetII, EthernetIIHeader, Arp, Tcp};
use std::cell::RefCell;
use std::collections::{BTreeMap, VecDeque};
use std::fs::File;
use std::io::{Read, Write};
use std::thread;
use std::io::{self, Read, Write};
use std::os::unix::io::FromRawFd;
use std::rc::Rc;
use std::{slice, str, thread};
use syscall::data::Packet;
use syscall::error::{Error, Result, EACCES, EADDRNOTAVAIL, EBADF, EINVAL, ENOENT, EWOULDBLOCK};
use syscall::flag::{EVENT_READ, O_NONBLOCK};
use syscall::scheme::SchemeMut;
use resource_scheme::ResourceScheme;
use syscall::Packet;
struct Interface {
mac: MacAddr,
ip: Ipv4Addr,
router: Ipv4Addr,
subnet: Ipv4Addr,
arp_file: File,
ip_file: File,
arp: BTreeMap<Ipv4Addr, MacAddr>,
rarp: BTreeMap<MacAddr, Ipv4Addr>,
}
use scheme::IpScheme;
impl Interface {
fn new(arp_fd: usize, ip_fd: usize) -> Self {
Interface {
mac: MacAddr::from_str(&getcfg("mac").unwrap()),
ip: Ipv4Addr::from_str(&getcfg("ip").unwrap()),
router: Ipv4Addr::from_str(&getcfg("ip_router").unwrap()),
subnet: Ipv4Addr::from_str(&getcfg("ip_subnet").unwrap()),
arp_file: unsafe { File::from_raw_fd(arp_fd) },
ip_file: unsafe { File::from_raw_fd(ip_fd) },
arp: BTreeMap::new(),
rarp: BTreeMap::new(),
}
}
}
mod resource;
mod scheme;
struct Handle {
proto: u8,
flags: usize,
events: usize,
data: VecDeque<Vec<u8>>,
todo: VecDeque<Packet>,
}
struct Ipd {
scheme_file: File,
interfaces: Vec<Interface>,
next_id: usize,
handles: BTreeMap<usize, Handle>,
}
impl Ipd {
fn new(scheme_file: File) -> Self {
Ipd {
scheme_file: scheme_file,
interfaces: Vec::new(),
next_id: 1,
handles: BTreeMap::new(),
}
}
fn scheme_event(&mut self) -> io::Result<()> {
loop {
let mut packet = Packet::default();
if self.scheme_file.read(&mut packet)? == 0 {
break;
}
let a = packet.a;
self.handle(&mut packet);
if packet.a == (-EWOULDBLOCK) as usize {
packet.a = a;
if let Some(mut handle) = self.handles.get_mut(&packet.b) {
handle.todo.push_back(packet);
}
} else {
self.scheme_file.write(&packet)?;
}
}
Ok(())
}
fn arp_event(&mut self, if_id: usize) -> io::Result<()> {
if let Some(mut interface) = self.interfaces.get_mut(if_id) {
loop {
let mut bytes = [0; 65536];
let count = interface.arp_file.read(&mut bytes)?;
if count == 0 {
break;
}
if let Some(frame) = EthernetII::from_bytes(&bytes[.. count]) {
if let Some(packet) = Arp::from_bytes(&frame.data) {
if packet.header.oper.get() == 1 {
if packet.header.dst_ip == interface.ip {
let mut response = Arp {
header: packet.header,
data: packet.data.clone(),
};
response.header.oper.set(2);
response.header.dst_mac = packet.header.src_mac;
response.header.dst_ip = packet.header.src_ip;
response.header.src_mac = interface.mac;
response.header.src_ip = interface.ip;
let mut response_frame = EthernetII {
header: frame.header,
data: response.to_bytes()
};
response_frame.header.dst = response_frame.header.src;
response_frame.header.src = interface.mac;
interface.arp_file.write(&response_frame.to_bytes())?;
}
}
}
}
}
}
Ok(())
}
fn ip_event(&mut self, if_id: usize) -> io::Result<()> {
if let Some(mut interface) = self.interfaces.get_mut(if_id) {
loop {
let mut bytes = [0; 65536];
let count = interface.ip_file.read(&mut bytes)?;
if count == 0 {
break;
}
if let Some(frame) = EthernetII::from_bytes(&bytes[.. count]) {
if let Some(ip) = Ipv4::from_bytes(&frame.data) {
if ip.header.dst == interface.ip || ip.header.dst == Ipv4Addr::BROADCAST {
//TODO: Handle ping here
for (id, handle) in self.handles.iter_mut() {
if ip.header.proto == handle.proto {
handle.data.push_back(frame.data.clone());
while ! handle.todo.is_empty() && ! handle.data.is_empty() {
let mut packet = handle.todo.pop_front().unwrap();
let buf = unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) };
let data = handle.data.pop_front().unwrap();
let mut i = 0;
while i < buf.len() && i < data.len() {
buf[i] = data[i];
i += 1;
}
packet.a = i;
self.scheme_file.write(&packet)?;
}
if handle.events & EVENT_READ == EVENT_READ {
if let Some(data) = handle.data.get(0) {
self.scheme_file.write(&Packet {
id: 0,
pid: 0,
uid: 0,
gid: 0,
a: syscall::number::SYS_FEVENT,
b: *id,
c: EVENT_READ,
d: data.len()
})?;
}
}
}
}
}
}
}
}
}
Ok(())
}
}
impl SchemeMut for Ipd {
fn open(&mut self, url: &[u8], flags: usize, uid: u32, _gid: u32) -> Result<usize> {
if uid == 0 {
let path = str::from_utf8(url).or(Err(Error::new(EINVAL)))?;
let proto = u8::from_str_radix(path, 16).or(Err(Error::new(ENOENT)))?;
let id = self.next_id;
self.next_id += 1;
self.handles.insert(id, Handle {
proto: proto,
flags: flags,
events: 0,
data: VecDeque::new(),
todo: VecDeque::new(),
});
Ok(id)
} else {
Err(Error::new(EACCES))
}
}
fn dup(&mut self, file: usize, _buf: &[u8]) -> Result<usize> {
let handle = {
let handle = self.handles.get(&file).ok_or(Error::new(EBADF))?;
Handle {
proto: handle.proto,
flags: handle.flags,
events: 0,
data: handle.data.clone(),
todo: VecDeque::new(),
}
};
let id = self.next_id;
self.next_id += 1;
self.handles.insert(id, handle);
Ok(id)
}
fn read(&mut self, file: usize, buf: &mut [u8]) -> Result<usize> {
let mut handle = self.handles.get_mut(&file).ok_or(Error::new(EBADF))?;
if let Some(data) = handle.data.pop_front() {
let mut i = 0;
while i < buf.len() && i < data.len() {
buf[i] = data[i];
i += 1;
}
Ok(i)
} else if handle.flags & O_NONBLOCK == O_NONBLOCK {
Ok(0)
} else {
Err(Error::new(EWOULDBLOCK))
}
}
fn write(&mut self, file: usize, buf: &[u8]) -> Result<usize> {
let handle = self.handles.get(&file).ok_or(Error::new(EBADF))?;
if let Some(mut ip) = Ipv4::from_bytes(buf) {
for mut interface in self.interfaces.iter_mut() {
if ip.header.src == interface.ip || ip.header.src == Ipv4Addr::NULL {
ip.header.src = interface.ip;
ip.header.proto = handle.proto;
if let Some(mut tcp) = Tcp::from_bytes(&ip.data) {
tcp.checksum(&ip.header.src, &ip.header.dst);
ip.data = tcp.to_bytes();
}
ip.checksum();
let frame = EthernetII {
header: EthernetIIHeader {
//TODO: Get real dst
dst: MacAddr::BROADCAST,
src: interface.mac,
ethertype: n16::new(0x800),
},
data: ip.to_bytes()
};
interface.ip_file.write(&frame.to_bytes()).map_err(|err| err.into_sys())?;
return Ok(buf.len());
}
}
Err(Error::new(EADDRNOTAVAIL))
} else {
Err(Error::new(EINVAL))
}
}
fn fevent(&mut self, file: usize, flags: usize) -> Result<usize> {
let mut handle = self.handles.get_mut(&file).ok_or(Error::new(EBADF))?;
handle.events = flags;
Ok(file)
}
fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result<usize> {
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
let path_string = format!("ip:{:X}", handle.proto);
let path = path_string.as_bytes();
let mut i = 0;
while i < buf.len() && i < path.len() {
buf[i] = path[i];
i += 1;
}
Ok(i)
}
fn fsync(&mut self, file: usize) -> Result<usize> {
let _handle = self.handles.get(&file).ok_or(Error::new(EBADF))?;
Ok(0)
}
fn close(&mut self, file: usize) -> Result<usize> {
let handle = self.handles.remove(&file).ok_or(Error::new(EBADF))?;
drop(handle);
Ok(0)
}
}
fn main() {
thread::spawn(move || {
let mut socket = File::create(":ip").expect("ipd: failed to create ip scheme");
let scheme = IpScheme::new();
loop {
let mut packet = Packet::default();
socket.read(&mut packet).expect("ipd: failed to read events from ip scheme");
scheme.handle(&mut packet);
socket.write(&packet).expect("ipd: failed to write responses to ip scheme");
let scheme_fd = syscall::open(":ip", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("ipd: failed to create :ip");
let scheme_file = unsafe { File::from_raw_fd(scheme_fd) };
let ipd = Rc::new(RefCell::new(Ipd::new(scheme_file)));
let mut event_queue = EventQueue::<()>::new().expect("ipd: failed to create event queue");
//TODO: Multiple interfaces
{
let arp_fd = syscall::open("ethernet:806", syscall::O_RDWR | syscall::O_NONBLOCK).expect("ipd: failed to open ethernet:806");
let ip_fd = syscall::open("ethernet:800", syscall::O_RDWR | syscall::O_NONBLOCK).expect("ipd: failed to open ethernet:800");
let if_id = {
let mut ipd = ipd.borrow_mut();
let if_id = ipd.interfaces.len();
ipd.interfaces.push(Interface::new(arp_fd, ip_fd));
if_id
};
let arp_ipd = ipd.clone();
event_queue.add(arp_fd, move |_count: usize| -> io::Result<Option<()>> {
arp_ipd.borrow_mut().arp_event(if_id)?;
Ok(None)
}).expect("ipd: failed to listen to events on ethernet:806");
let ip_ipd = ipd.clone();
event_queue.add(ip_fd, move |_count: usize| -> io::Result<Option<()>> {
ip_ipd.borrow_mut().ip_event(if_id)?;
Ok(None)
}).expect("ipd: failed to listen to events on ethernet:800");
}
event_queue.add(scheme_fd, move |_count: usize| -> io::Result<Option<()>> {
ipd.borrow_mut().scheme_event()?;
Ok(None)
}).expect("ipd: failed to listen to events on :ip");
// Make sure that all descriptors are at EOF
event_queue.trigger_all(0).expect("ipd: failed to trigger event queue");
event_queue.run().expect("ipd: failed to run event queue");
});
}
#[cfg(test)]
fn test() {
use scheme::IpScheme;
println!("* Test that we can read a simple packet from the same connection.");
let bytes = "TEST".as_bytes();
let mut scheme = IpScheme::new();
let a = scheme.open(&"ip:127.0.0.1/11".as_bytes(), 0, 0, 0).unwrap();
let num_bytes_written = scheme.write(a, bytes).unwrap();
assert_eq!(num_bytes_written, bytes.len());
let mut buf = [0;65536];
let num_bytes_read = scheme.read(a, &mut buf).unwrap();
assert_eq!(num_bytes_read, num_bytes_written);
let bytes_read = &buf[0..num_bytes_read];
assert_eq!(bytes, bytes_read);
println!("* Test that the loopback is now empty.");
let num_bytes_read = scheme.read(a, &mut buf).unwrap();
assert_eq!(num_bytes_read, 0);
println!("* Test that we can read the same packet from a different connection.");
let num_bytes_written = scheme.write(a, bytes).unwrap();
assert_eq!(num_bytes_written, bytes.len());
let b = scheme.open("ip:127.0.0.1/11".as_bytes(), 0, 0, 0).unwrap();
let num_bytes_read = scheme.read(b, &mut buf).unwrap();
assert_eq!(num_bytes_read, num_bytes_written);
let bytes_read = &buf[0..num_bytes_read];
assert_eq!(bytes, bytes_read);
println!("* Test that the loopback is now empty for both connections.");
let num_bytes_read = scheme.read(a, &mut buf).unwrap();
assert_eq!(num_bytes_read, 0);
let num_bytes_read = scheme.read(b, &mut buf).unwrap();
assert_eq!(num_bytes_read, 0);
println!("* Push a number of packets, check that we get them in the right order.");
let mut payloads : Vec<String> = (0..100).map(|i| format!("TEST {}", i)).collect();
for payload in &payloads {
let bytes = payload.into_bytes();
let num_bytes_written = scheme.write(a, &bytes).unwrap();
assert_eq!(bytes.len(), num_bytes_written);
}
for payload in &payloads {
let bytes = payload.into_bytes();
let mut buf = [0;65536];
let num_bytes_read = scheme.read(a, &mut buf).unwrap();
assert_eq!(bytes.len(), num_bytes_read);
let bytes_read = &buf[0..num_bytes_read];
assert_eq!(bytes, bytes_read);
}
}

View file

@ -1,242 +0,0 @@
use std::cell::RefCell;
use std::{cmp, mem};
use std::collections::VecDeque;
use std::rc::Rc;
use std::sync::Mutex;
use netutils::{n16, Ipv4Addr, Checksum, Ipv4Header, Ipv4};
use resource_scheme::Resource;
use syscall;
use syscall::error::*;
/// Max number of bytes in a packet.
const MAX_PACKET_LENGTH : usize = 65536;
/// A IP (internet protocol) resource.
///
/// Each instance represents a connection (~ a IP socket).
pub struct IpResource {
/// The underlying mechanism ensured to connect to the peer.
pub connection: Connection,
/// The IP address of the host (i.e. this machine).
pub host_addr: Ipv4Addr,
/// The IP address of the peer (i.e. the other machine).
pub peer_addr: Ipv4Addr,
/// The IP protocol used by this connection. See
/// http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml
/// for the list of valid protocols.
pub proto: u8,
/// The id of the next packet being sent.
/// See https://en.wikipedia.org/wiki/IPv4#Identification .
pub id: u16,
}
pub enum Connection {
Device {
/// Link to the underlying device (typically, an Ethernet card).
link: usize,
/// If this connection was opened waiting for a peer (i.e. `ip:/protocol`),
/// the data received when the peer actually connected. Otherwise, empty.
/// Emptied during the first call to `read()`.
init_data: Vec<u8>,
},
Loopback {
/// FIFO queue of packets written to the loopback and waiting to be read.
///
/// The data stored contains the exact data that has been added by the client
/// calling `write()`, without adding any headers.
///
/// This buffer is shared between all loopback connections.
packets: Rc<RefCell<VecDeque<Vec<u8>>>>
}
}
impl Resource for IpResource {
/// Duplicate the connection.
///
/// This duplicates both `self.link` and `self.init_data`.
///
/// # Errors
///
/// Fails if the `link` to the underlying device cannot be
/// duplicated.
fn dup(&self) -> Result<Box<Self>> {
use self::Connection::*;
let connection = match self.connection {
Loopback { ref packets }=> Loopback { packets: packets.clone() },
Device { link, ref init_data } => {
let link = try!(syscall::dup(link));
let init_data = init_data.clone();
Device {
link: link,
init_data: init_data
}
}
};
Ok(Box::new(IpResource {
host_addr: self.host_addr,
peer_addr: self.peer_addr,
proto: self.proto,
id: self.id,
connection: connection,
}))
}
/// Get the current path, as `ip:peer/protocol`, where `peer`
/// is the IPv4 address of the peer and `protocol` is the hex-based
/// number of the IP protocol used.
///
/// Note that the `peer` is specified even if the connection was initially
/// created as `ip:/protocol`.
fn path(&self, buf: &mut [u8]) -> Result<usize> {
let path_string = format!("ip:{}/{:X}", self.peer_addr.to_string(), self.proto);
let path = path_string.as_bytes();
for (b, p) in buf.iter_mut().zip(path.iter()) {
*b = *p;
}
Ok(cmp::min(buf.len(), path.len()))
}
/// Read data from the device.
///
/// If some data has already been made available during the establishment
/// of the connection, this data is (entirely) read during the first call
/// to `read()`, without attempting to actually read from the device. This
/// can happen only if the connection was waiting for a remote peer to connect, i.e.
/// with a url `ip:/protocol`, without host.
///
/// If this connection is a loopback, oldest unread packet written is read.
///
/// # Errors
///
/// Fails if the call to `syscall::read()` fails for this device.
///
/// # Data loss
///
/// If `buf` is too small, *exceeding data is discarded*. To be sure that you read
/// all data, you should provide a 64kb `buf`.
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
use self::Connection::*;
match self.connection {
Loopback { ref packets }=> {
match packets.borrow_mut().pop_front() {
None => Ok(0),
Some(data) => {
for (b, d) in buf.iter_mut().zip(data.iter()) {
*b = *d;
}
// Note: We're discarding excess `data`.
Ok(cmp::min(buf.len(), data.len()))
}
}
}
Device { ref mut init_data, link } => {
if !init_data.is_empty() {
let mut data: Vec<u8> = Vec::new();
mem::swap(init_data, &mut data);
for (b, d) in buf.iter_mut().zip(data.iter()) {
*b = *d;
}
return Ok(cmp::min(buf.len(), data.len()));
}
let mut bytes = [0; MAX_PACKET_LENGTH];
let count = try!(syscall::read(link, &mut bytes));
if let Some(packet) = Ipv4::from_bytes(&bytes[..count]) {
if packet.header.proto == self.proto &&
(packet.header.dst.equals(self.host_addr) || packet.header.dst.equals(Ipv4Addr::BROADCAST)) &&
(packet.header.src.equals(self.peer_addr) || self.peer_addr.equals(Ipv4Addr::BROADCAST)) {
for (b, d) in buf.iter_mut().zip(packet.data.iter()) {
*b = *d;
}
return Ok(cmp::min(buf.len(), packet.data.len()));
}
}
Ok(0)
}
}
}
/// Send data to the peer.
///
/// # Errors
///
/// Fails if the call to `syscall::write()` fails for this device.
fn write(&mut self, buf: &[u8]) -> Result<usize> {
use self::Connection::*;
let ip_data = Vec::from(buf);
match self.connection {
Loopback { ref packets } => {
// Make sure that we're not going to store data that can't be read.
let buf =
if buf.len() > MAX_PACKET_LENGTH {
&buf[0..MAX_PACKET_LENGTH]
} else {
buf
};
packets.borrow_mut().push_back(buf.to_vec());
return Ok(buf.len())
}
Device { link, .. } => {
self.id += 1;
let mut ip = Ipv4 {
header: Ipv4Header {
ver_hlen: 0x40 | (mem::size_of::<Ipv4Header>() / 4 & 0xF) as u8, // No Options
services: 0,
len: n16::new((mem::size_of::<Ipv4Header>() + ip_data.len()) as u16), // No Options
id: n16::new(self.id),
flags_fragment: n16::new(0),
ttl: 128,
proto: self.proto,
checksum: Checksum { data: 0 },
src: self.host_addr,
dst: self.peer_addr,
},
options: Vec::new(),
data: ip_data,
};
unsafe {
let header_ptr: *const Ipv4Header = &ip.header;
ip.header.checksum.data =
Checksum::compile(Checksum::sum(header_ptr as usize, mem::size_of::<Ipv4Header>()) +
Checksum::sum(ip.options.as_ptr() as usize, ip.options.len()));
}
match syscall::write(link, &ip.to_bytes()) {
Ok(_) => Ok(buf.len()),
Err(err) => Err(err),
}
}
}
}
fn sync(&mut self) -> Result<usize> {
if let Connection::Device { link, .. } = self.connection {
syscall::fsync(link)
} else {
Ok(0)
}
}
}
impl Drop for IpResource {
fn drop(&mut self) {
if let Connection::Device { link, .. } = self.connection {
let _ = syscall::close(link);
}
}
}

View file

@ -1,193 +0,0 @@
use std::cell::RefCell;
use std::collections::VecDeque;
use std::rand;
use std::rc::Rc;
use std::{str, u16};
use netutils::{getcfg, n16, MacAddr, Ipv4Addr, ArpHeader, Arp, Ipv4};
use resource_scheme::ResourceScheme;
use syscall;
use syscall::error::{Error, Result, EACCES, ENOENT, EINVAL};
use syscall::flag::O_RDWR;
use resource::*;
/// The IP address of the localhost.
const LOCALHOST: Ipv4Addr = Ipv4Addr { bytes: [127, 0, 0, 1] };
/// A ARP entry (MAC + IP)
pub struct ArpEntry {
ip: Ipv4Addr,
mac: MacAddr,
}
/// A IP scheme
pub struct IpScheme {
pub arp: RefCell<Vec<ArpEntry>>,
/// FIFO queue of packets written to the loopback and waiting to be read.
///
/// The data stored contains the exact data that has been added by the client
/// calling `write()`, without adding any headers.
///
/// This buffer is shared between all loopback connections.
pub loopback_fifo: Rc<RefCell<VecDeque<Vec<u8>>>>,
}
impl IpScheme {
pub fn new() -> IpScheme {
IpScheme {
arp: RefCell::new(Vec::new()),
loopback_fifo: Rc::new(RefCell::new(VecDeque::new())),
}
}
}
impl ResourceScheme<IpResource> for IpScheme {
fn open_resource(&self, url: &[u8], _flags: usize, uid: u32, _gid: u32) -> Result<Box<IpResource>> {
if uid == 0 {
let mac_addr = MacAddr::from_str(&getcfg("mac").map_err(|err| err.into_sys())?);
let ip_addr = Ipv4Addr::from_str(&getcfg("ip").map_err(|err| err.into_sys())?);
let ip_subnet = Ipv4Addr::from_str(&getcfg("ip_subnet").map_err(|err| err.into_sys())?);
let ip_router = Ipv4Addr::from_str(&getcfg("ip_router").map_err(|err| err.into_sys())?);
let path = try!(str::from_utf8(url).or(Err(Error::new(EINVAL))));
let mut parts = path.split('/');
if let Some(host_string) = parts.next() {
if let Some(proto_string) = parts.next() {
let proto = u8::from_str_radix(proto_string, 16).unwrap_or(0);
if ! host_string.is_empty() {
let peer_addr = Ipv4Addr::from_str(host_string);
let mut route_mac = MacAddr::BROADCAST;
if ! peer_addr.equals(Ipv4Addr::BROADCAST) {
if peer_addr.equals(LOCALHOST) {
return Ok(Box::new(IpResource {
connection: Connection::Loopback {
packets: self.loopback_fifo.clone()
},
host_addr: ip_addr,
peer_addr: peer_addr,
proto: proto,
id: (rand() % 65536) as u16,
}));
}
let mut needs_routing = false;
for octet in 0..4 {
let me = ip_addr.bytes[octet];
let mask = ip_subnet.bytes[octet];
let them = peer_addr.bytes[octet];
if me & mask != them & mask {
needs_routing = true;
break;
}
}
let route_addr = if needs_routing {
ip_router
} else {
peer_addr
};
for entry in self.arp.borrow().iter() {
if entry.ip.equals(route_addr) {
route_mac = entry.mac;
break;
}
}
if route_mac.equals(MacAddr::BROADCAST) {
if let Ok(link) = syscall::open(&format!("ethernet:{}/806", &route_mac.to_string()), O_RDWR) {
let arp = Arp {
header: ArpHeader {
htype: n16::new(1),
ptype: n16::new(0x800),
hlen: 6,
plen: 4,
oper: n16::new(1),
src_mac: mac_addr,
src_ip: ip_addr,
dst_mac: route_mac,
dst_ip: route_addr,
},
data: Vec::new(),
};
match syscall::write(link, &arp.to_bytes()) {
Ok(_) => loop {
let mut bytes = [0; 65536];
match syscall::read(link, &mut bytes) {
Ok(count) => if let Some(packet) = Arp::from_bytes(&bytes[..count]) {
if packet.header.oper.get() == 2 &&
packet.header.src_ip.equals(route_addr) {
route_mac = packet.header.src_mac;
self.arp.borrow_mut().push(ArpEntry {
ip: route_addr,
mac: route_mac,
});
break;
}
},
Err(_) => (),
}
},
Err(err) => println!("IP: ARP Write Failed: {}", err),
}
}
}
}
if let Ok(link) = syscall::open(&format!("ethernet:{}/800", &route_mac.to_string()), O_RDWR) {
return Ok(Box::new(IpResource {
connection: Connection::Device {
link: link,
init_data: Vec::new(),
},
host_addr: ip_addr,
peer_addr: peer_addr,
proto: proto,
id: (rand() % 65536) as u16,
}));
}
} else {
while let Ok(link) = syscall::open("ethernet:/800", O_RDWR) {
let mut bytes = [0; 65536];
// FIXME: Blocking call?
match syscall::read(link, &mut bytes) {
Ok(count) => {
if let Some(packet) = Ipv4::from_bytes(&bytes[..count]) {
if packet.header.proto == proto &&
(packet.header.dst.equals(ip_addr) || packet.header.dst.equals(Ipv4Addr::BROADCAST)) {
return Ok(Box::new(IpResource {
connection: Connection::Device {
link: link,
init_data: packet.data,
},
host_addr: ip_addr,
peer_addr: packet.header.src,
proto: proto,
id: (rand() % 65536) as u16,
}));
}
}
}
Err(_) => break,
}
}
}
} else {
println!("IP: No protocol provided");
}
} else {
println!("IP: No host provided");
}
Err(Error::new(ENOENT))
} else {
Err(Error::new(EACCES))
}
}
}

@ -1 +1 @@
Subproject commit 601c5685f058c9276d896262195b50c75a6d7a97
Subproject commit 1d554eda337b9d75a4c0b209c3b399b8f1148f35

View file

@ -16,7 +16,7 @@ impl Scheme for RandScheme {
Ok(0)
}
fn dup(&self, file: usize) -> Result<usize> {
fn dup(&self, file: usize, _buf: &[u8]) -> Result<usize> {
Ok(file)
}

@ -1 +1 @@
Subproject commit 3dcaad55fe6e82450c1691da5d515861a7deed0a
Subproject commit ec00f58d73de142332e80d097e32f3d93c2a33bf

View file

@ -3,6 +3,7 @@ name = "tcpd"
version = "0.1.0"
[dependencies]
event = { path = "../../crates/event/" }
netutils = { path = "../../programs/netutils/" }
resource_scheme = { path = "../../crates/resource_scheme/" }
rand = { git = "https://github.com/redox-os/rand.git" }
syscall = { path = "../../syscall/" }

View file

@ -1,30 +1,680 @@
#![feature(rand)]
extern crate event;
extern crate netutils;
extern crate resource_scheme;
extern crate rand;
extern crate syscall;
use rand::{Rng, OsRng};
use std::collections::{BTreeMap, VecDeque};
use std::cell::RefCell;
use std::fs::File;
use std::io::{Read, Write};
use std::thread;
use std::io::{self, Read, Write};
use std::{mem, slice, str, thread};
use std::os::unix::io::FromRawFd;
use std::rc::Rc;
use resource_scheme::ResourceScheme;
use syscall::Packet;
use event::EventQueue;
use netutils::{n16, n32, Ipv4, Ipv4Addr, Ipv4Header, Tcp, TcpHeader, Checksum, TCP_FIN, TCP_SYN, TCP_RST, TCP_PSH, TCP_ACK};
use syscall::data::Packet;
use syscall::error::{Error, Result, EACCES, EADDRINUSE, EBADF, EINVAL, EISCONN, EMSGSIZE, ENOTCONN, EWOULDBLOCK};
use syscall::flag::{EVENT_READ, O_CREAT, O_RDWR, O_NONBLOCK};
use syscall::scheme::SchemeMut;
use scheme::TcpScheme;
fn parse_socket(socket: &str) -> (Ipv4Addr, u16) {
let mut socket_parts = socket.split(":");
let host = Ipv4Addr::from_str(socket_parts.next().unwrap_or(""));
let port = socket_parts.next().unwrap_or("").parse::<u16>().unwrap_or(0);
(host, port)
}
mod resource;
mod scheme;
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
enum State {
Listen,
SynSent,
SynReceived,
Established,
FinWait1,
FinWait2,
CloseWait,
Closing,
LastAck,
TimeWait,
Closed
}
struct Handle {
local: (Ipv4Addr, u16),
remote: (Ipv4Addr, u16),
flags: usize,
events: usize,
state: State,
seq: u32,
ack: u32,
data: VecDeque<(Ipv4, Tcp)>,
todo_dup: VecDeque<Packet>,
todo_read: VecDeque<Packet>,
todo_write: VecDeque<Packet>,
}
impl Handle {
fn is_connected(&self) -> bool {
self.remote.0 != Ipv4Addr::NULL && self.remote.1 != 0
}
fn read_closed(&self) -> bool {
self.state == State::CloseWait || self.state == State::LastAck || self.state == State::TimeWait || self.state == State::Closed
}
fn matches(&self, ip: &Ipv4, tcp: &Tcp) -> bool {
// Local address not set or IP dst matches or is broadcast
(self.local.0 == Ipv4Addr::NULL || ip.header.dst == self.local.0 || ip.header.dst == Ipv4Addr::BROADCAST)
// Local port matches UDP dst
&& tcp.header.dst.get() == self.local.1
// Remote address not set or is broadcast, or IP src matches
&& (self.remote.0 == Ipv4Addr::NULL || self.remote.0 == Ipv4Addr::BROADCAST || ip.header.src == self.remote.0)
// Remote port not set or UDP src matches
&& (self.remote.1 == 0 || tcp.header.src.get() == self.remote.1)
}
fn create_tcp(&self, flags: u16, data: Vec<u8>) -> Tcp {
Tcp {
header: TcpHeader {
src: n16::new(self.local.1),
dst: n16::new(self.remote.1),
sequence: n32::new(self.seq),
ack_num: n32::new(self.ack),
flags: n16::new(((mem::size_of::<TcpHeader>() << 10) & 0xF000) as u16 | (flags & 0xFFF)),
window_size: n16::new(8192),
checksum: Checksum { data: 0 },
urgent_pointer: n16::new(0),
},
options: Vec::new(),
data: data
}
}
fn create_ip(&self, id: u16, data: Vec<u8>) -> Ipv4 {
Ipv4 {
header: Ipv4Header {
ver_hlen: 0x45,
services: 0,
len: n16::new((data.len() + mem::size_of::<Ipv4Header>()) as u16),
id: n16::new(id),
flags_fragment: n16::new(0),
ttl: 127,
proto: 0x06,
checksum: Checksum { data: 0 },
src: self.local.0,
dst: self.remote.0
},
options: Vec::new(),
data: data
}
}
}
struct Tcpd {
scheme_file: File,
tcp_file: File,
ports: BTreeMap<u16, usize>,
next_id: usize,
handles: BTreeMap<usize, Handle>,
rng: OsRng,
}
impl Tcpd {
fn new(scheme_file: File, tcp_file: File) -> Self {
Tcpd {
scheme_file: scheme_file,
tcp_file: tcp_file,
ports: BTreeMap::new(),
next_id: 1,
handles: BTreeMap::new(),
rng: OsRng::new().expect("tcpd: failed to open RNG")
}
}
fn scheme_event(&mut self) -> io::Result<()> {
loop {
let mut packet = Packet::default();
if self.scheme_file.read(&mut packet)? == 0 {
break;
}
let a = packet.a;
self.handle(&mut packet);
if packet.a == (-EWOULDBLOCK) as usize {
if let Some(mut handle) = self.handles.get_mut(&packet.b) {
match a {
syscall::number::SYS_DUP => {
packet.a = a;
handle.todo_dup.push_back(packet);
},
syscall::number::SYS_READ => {
packet.a = a;
handle.todo_read.push_back(packet);
},
syscall::number::SYS_WRITE => {
packet.a = a;
handle.todo_write.push_back(packet);
},
_ => {
self.scheme_file.write(&packet)?;
}
}
}
} else {
self.scheme_file.write(&packet)?;
}
}
Ok(())
}
fn tcp_event(&mut self) -> io::Result<()> {
loop {
let mut bytes = [0; 65536];
let count = self.tcp_file.read(&mut bytes)?;
if count == 0 {
break;
}
if let Some(ip) = Ipv4::from_bytes(&bytes[.. count]) {
if let Some(tcp) = Tcp::from_bytes(&ip.data) {
let mut closing = Vec::new();
let mut found_connection = false;
for (id, handle) in self.handles.iter_mut() {
if handle.state != State::Listen && handle.matches(&ip, &tcp) {
found_connection = true;
match handle.state {
State::SynReceived => if tcp.header.flags.get() & (TCP_SYN | TCP_ACK) == TCP_ACK && tcp.header.ack_num.get() == handle.seq {
handle.state = State::Established;
},
State::SynSent => if tcp.header.flags.get() & (TCP_SYN | TCP_ACK) == TCP_SYN | TCP_ACK && tcp.header.ack_num.get() == handle.seq {
handle.state = State::Established;
handle.ack = tcp.header.sequence.get() + 1;
let tcp = handle.create_tcp(TCP_ACK, Vec::new());
let ip = handle.create_ip(self.rng.gen(), tcp.to_bytes());
self.tcp_file.write(&ip.to_bytes())?;
},
State::Established => if tcp.header.flags.get() & (TCP_SYN | TCP_ACK) == TCP_ACK && tcp.header.ack_num.get() == handle.seq {
handle.ack = tcp.header.sequence.get();
if ! tcp.data.is_empty() {
handle.data.push_back((ip.clone(), tcp.clone()));
handle.ack += tcp.data.len() as u32;
let tcp = handle.create_tcp(TCP_ACK, Vec::new());
let ip = handle.create_ip(self.rng.gen(), tcp.to_bytes());
self.tcp_file.write(&ip.to_bytes())?;
} else if tcp.header.flags.get() & TCP_FIN == TCP_FIN {
handle.state = State::CloseWait;
handle.ack += 1;
let tcp = handle.create_tcp(TCP_ACK, Vec::new());
let ip = handle.create_ip(self.rng.gen(), tcp.to_bytes());
self.tcp_file.write(&ip.to_bytes())?;
}
},
//TODO: Time wait
State::FinWait1 => if tcp.header.flags.get() & (TCP_SYN | TCP_ACK) == TCP_ACK && tcp.header.ack_num.get() == handle.seq {
handle.ack = tcp.header.sequence.get() + 1;
if tcp.header.flags.get() & TCP_FIN == TCP_FIN {
handle.state = State::TimeWait;
let tcp = handle.create_tcp(TCP_ACK, Vec::new());
let ip = handle.create_ip(self.rng.gen(), tcp.to_bytes());
self.tcp_file.write(&ip.to_bytes())?;
closing.push(*id);
} else {
handle.state = State::FinWait2;
}
},
State::FinWait2 => if tcp.header.flags.get() & (TCP_SYN | TCP_ACK | TCP_FIN) == TCP_ACK | TCP_FIN && tcp.header.ack_num.get() == handle.seq {
handle.ack = tcp.header.sequence.get() + 1;
handle.state = State::TimeWait;
let tcp = handle.create_tcp(TCP_ACK, Vec::new());
let ip = handle.create_ip(self.rng.gen(), tcp.to_bytes());
self.tcp_file.write(&ip.to_bytes())?;
closing.push(*id);
},
State::LastAck => if tcp.header.flags.get() & (TCP_SYN | TCP_ACK) == TCP_ACK && tcp.header.ack_num.get() == handle.seq {
handle.state = State::Closed;
closing.push(*id);
},
_ => ()
}
while ! handle.todo_read.is_empty() && (! handle.data.is_empty() || handle.read_closed()) {
let mut packet = handle.todo_read.pop_front().unwrap();
let buf = unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) };
if let Some((_ip, tcp)) = handle.data.pop_front() {
let mut i = 0;
while i < buf.len() && i < tcp.data.len() {
buf[i] = tcp.data[i];
i += 1;
}
packet.a = i;
} else {
packet.a = 0;
}
self.scheme_file.write(&packet)?;
}
if ! handle.todo_write.is_empty() && handle.state == State::Established {
let mut packet = handle.todo_write.pop_front().unwrap();
let buf = unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) };
let tcp = handle.create_tcp(TCP_ACK | TCP_PSH, buf.to_vec());
let ip = handle.create_ip(self.rng.gen(), tcp.to_bytes());
let result = self.tcp_file.write(&ip.to_bytes()).map_err(|err| err.into_sys());
if result.is_ok() {
handle.seq += buf.len() as u32;
}
packet.a = Error::mux(result.and(Ok(buf.len())));
self.scheme_file.write(&packet)?;
}
if handle.events & EVENT_READ == EVENT_READ {
if let Some(&(ref _ip, ref tcp)) = handle.data.get(0) {
self.scheme_file.write(&Packet {
id: 0,
pid: 0,
uid: 0,
gid: 0,
a: syscall::number::SYS_FEVENT,
b: *id,
c: EVENT_READ,
d: tcp.data.len()
})?;
}
}
}
}
for file in closing {
let handle = self.handles.remove(&file).unwrap();
let remove = if let Some(mut port) = self.ports.get_mut(&handle.local.1) {
*port = *port + 1;
*port == 0
} else {
false
};
if remove {
self.ports.remove(&handle.local.1);
}
}
if ! found_connection && tcp.header.flags.get() & (TCP_SYN | TCP_ACK) == TCP_SYN {
let mut new_handles = Vec::new();
for (_id, handle) in self.handles.iter_mut() {
if handle.state == State::Listen && handle.matches(&ip, &tcp) {
handle.data.push_back((ip.clone(), tcp.clone()));
while ! handle.todo_dup.is_empty() && ! handle.data.is_empty() {
let mut packet = handle.todo_dup.pop_front().unwrap();
let (ip, tcp) = handle.data.pop_front().unwrap();
let mut new_handle = Handle {
local: handle.local,
remote: (ip.header.src, tcp.header.src.get()),
flags: handle.flags,
events: 0,
state: State::SynReceived,
seq: self.rng.gen(),
ack: tcp.header.sequence.get() + 1,
data: VecDeque::new(),
todo_dup: VecDeque::new(),
todo_read: VecDeque::new(),
todo_write: VecDeque::new(),
};
let tcp = new_handle.create_tcp(TCP_SYN | TCP_ACK, Vec::new());
let ip = new_handle.create_ip(self.rng.gen(), tcp.to_bytes());
self.tcp_file.write(&ip.to_bytes())?;
new_handle.seq += 1;
handle.data.retain(|&(ref ip, ref tcp)| {
if new_handle.matches(ip, tcp) {
false
} else {
true
}
});
if let Some(mut port) = self.ports.get_mut(&handle.local.1) {
*port = *port + 1;
}
let id = self.next_id;
self.next_id += 1;
packet.a = id;
new_handles.push((packet, new_handle));
}
}
}
for (packet, new_handle) in new_handles {
self.handles.insert(packet.a, new_handle);
self.scheme_file.write(&packet)?;
}
}
}
}
}
Ok(())
}
}
impl SchemeMut for Tcpd {
fn open(&mut self, url: &[u8], flags: usize, uid: u32, _gid: u32) -> Result<usize> {
let path = str::from_utf8(url).or(Err(Error::new(EINVAL)))?;
let mut parts = path.split("/");
let remote = parse_socket(parts.next().unwrap_or(""));
let mut local = parse_socket(parts.next().unwrap_or(""));
if local.1 == 0 {
local.1 = self.rng.gen_range(32768, 65535);
}
if local.1 <= 1024 && uid != 0 {
return Err(Error::new(EACCES));
}
if self.ports.contains_key(&local.1) {
return Err(Error::new(EADDRINUSE));
}
let mut handle = Handle {
local: local,
remote: remote,
flags: flags,
events: 0,
state: State::Listen,
seq: 0,
ack: 0,
data: VecDeque::new(),
todo_dup: VecDeque::new(),
todo_read: VecDeque::new(),
todo_write: VecDeque::new(),
};
if handle.is_connected() {
handle.seq = self.rng.gen();
handle.ack = 0;
handle.state = State::SynSent;
let tcp = handle.create_tcp(TCP_SYN, Vec::new());
let ip = handle.create_ip(self.rng.gen(), tcp.to_bytes());
self.tcp_file.write(&ip.to_bytes()).map_err(|err| err.into_sys())?;
handle.seq += 1;
}
self.ports.insert(local.1, 1);
let id = self.next_id;
self.next_id += 1;
self.handles.insert(id, handle);
Ok(id)
}
fn dup(&mut self, file: usize, buf: &[u8]) -> Result<usize> {
let path = str::from_utf8(buf).or(Err(Error::new(EINVAL)))?;
let handle = {
let mut handle = self.handles.get_mut(&file).ok_or(Error::new(EBADF))?;
let mut new_handle = Handle {
local: handle.local,
remote: handle.remote,
flags: handle.flags,
events: 0,
state: handle.state,
seq: handle.seq,
ack: handle.ack,
data: VecDeque::new(),
todo_dup: VecDeque::new(),
todo_read: VecDeque::new(),
todo_write: VecDeque::new(),
};
if path == "listen" {
if handle.is_connected() {
return Err(Error::new(EISCONN));
} else if let Some((ip, tcp)) = handle.data.pop_front() {
new_handle.remote = (ip.header.src, tcp.header.src.get());
new_handle.seq = self.rng.gen();
new_handle.ack = tcp.header.sequence.get() + 1;
new_handle.state = State::SynReceived;
let tcp = new_handle.create_tcp(TCP_SYN | TCP_ACK, Vec::new());
let ip = new_handle.create_ip(self.rng.gen(), tcp.to_bytes());
self.tcp_file.write(&ip.to_bytes()).map_err(|err| err.into_sys()).and(Ok(buf.len()))?;
new_handle.seq += 1;
} else {
return Err(Error::new(EWOULDBLOCK));
}
handle.data.retain(|&(ref ip, ref tcp)| {
if new_handle.matches(ip, tcp) {
false
} else {
true
}
});
} else if path.is_empty() {
new_handle.data = handle.data.clone();
} else if handle.is_connected() {
return Err(Error::new(EISCONN));
} else {
new_handle.remote = parse_socket(path);
if new_handle.is_connected() {
new_handle.seq = self.rng.gen();
new_handle.ack = 0;
new_handle.state = State::SynSent;
handle.data.retain(|&(ref ip, ref tcp)| {
if new_handle.matches(ip, tcp) {
new_handle.data.push_back((ip.clone(), tcp.clone()));
false
} else {
true
}
});
let tcp = new_handle.create_tcp(TCP_SYN, Vec::new());
let ip = new_handle.create_ip(self.rng.gen(), tcp.to_bytes());
self.tcp_file.write(&ip.to_bytes()).map_err(|err| err.into_sys()).and(Ok(buf.len()))?;
} else {
return Err(Error::new(EINVAL));
}
}
new_handle
};
if let Some(mut port) = self.ports.get_mut(&handle.local.1) {
*port = *port + 1;
}
let id = self.next_id;
self.next_id += 1;
self.handles.insert(id, handle);
Ok(id)
}
fn read(&mut self, file: usize, buf: &mut [u8]) -> Result<usize> {
let mut handle = self.handles.get_mut(&file).ok_or(Error::new(EBADF))?;
if ! handle.is_connected() {
Err(Error::new(ENOTCONN))
} else if let Some((_ip, tcp)) = handle.data.pop_front() {
let mut i = 0;
while i < buf.len() && i < tcp.data.len() {
buf[i] = tcp.data[i];
i += 1;
}
Ok(i)
} else if handle.flags & O_NONBLOCK == O_NONBLOCK || handle.read_closed() {
Ok(0)
} else {
Err(Error::new(EWOULDBLOCK))
}
}
fn write(&mut self, file: usize, buf: &[u8]) -> Result<usize> {
let mut handle = self.handles.get_mut(&file).ok_or(Error::new(EBADF))?;
if ! handle.is_connected() {
Err(Error::new(ENOTCONN))
} else if buf.len() >= 65507 {
Err(Error::new(EMSGSIZE))
} else {
match handle.state {
State::Established => {
let tcp = handle.create_tcp(TCP_ACK | TCP_PSH, buf.to_vec());
let ip = handle.create_ip(self.rng.gen(), tcp.to_bytes());
self.tcp_file.write(&ip.to_bytes()).map_err(|err| err.into_sys())?;
handle.seq += buf.len() as u32;
Ok(buf.len())
},
_ => {
Err(Error::new(EWOULDBLOCK))
}
}
}
}
fn fevent(&mut self, file: usize, flags: usize) -> Result<usize> {
let mut handle = self.handles.get_mut(&file).ok_or(Error::new(EBADF))?;
handle.events = flags;
Ok(file)
}
fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result<usize> {
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
let path_string = format!("tcp:{}:{}/{}:{}", handle.remote.0.to_string(), handle.remote.1, handle.local.0.to_string(), handle.local.1);
let path = path_string.as_bytes();
let mut i = 0;
while i < buf.len() && i < path.len() {
buf[i] = path[i];
i += 1;
}
Ok(i)
}
fn fsync(&mut self, file: usize) -> Result<usize> {
let _handle = self.handles.get(&file).ok_or(Error::new(EBADF))?;
Ok(0)
}
fn close(&mut self, file: usize) -> Result<usize> {
let closed = {
let mut handle = self.handles.get_mut(&file).ok_or(Error::new(EBADF))?;
match handle.state {
State::SynReceived | State::Established => {
handle.state = State::FinWait1;
let tcp = handle.create_tcp(TCP_FIN | TCP_ACK, Vec::new());
let ip = handle.create_ip(self.rng.gen(), tcp.to_bytes());
self.tcp_file.write(&ip.to_bytes()).map_err(|err| err.into_sys())?;
handle.seq += 1;
false
},
State::CloseWait => {
handle.state = State::LastAck;
let tcp = handle.create_tcp(TCP_FIN | TCP_ACK, Vec::new());
let ip = handle.create_ip(self.rng.gen(), tcp.to_bytes());
self.tcp_file.write(&ip.to_bytes()).map_err(|err| err.into_sys())?;
handle.seq += 1;
false
},
_ => true
}
};
if closed {
let handle = self.handles.remove(&file).ok_or(Error::new(EBADF))?;
let remove = if let Some(mut port) = self.ports.get_mut(&handle.local.1) {
*port = *port + 1;
*port == 0
} else {
false
};
if remove {
self.ports.remove(&handle.local.1);
}
}
Ok(0)
}
}
fn main() {
thread::spawn(move || {
let mut socket = File::create(":tcp").expect("tcpd: failed to create tcp scheme");
let scheme = TcpScheme;
loop {
let mut packet = Packet::default();
socket.read(&mut packet).expect("tcpd: failed to read events from tcp scheme");
scheme.handle(&mut packet);
socket.write(&packet).expect("tcpd: failed to write responses to tcp scheme");
}
let scheme_fd = syscall::open(":tcp", O_RDWR | O_CREAT | O_NONBLOCK).expect("tcpd: failed to create :tcp");
let scheme_file = unsafe { File::from_raw_fd(scheme_fd) };
let tcp_fd = syscall::open("ip:6", O_RDWR | O_NONBLOCK).expect("tcpd: failed to open ip:6");
let tcp_file = unsafe { File::from_raw_fd(tcp_fd) };
let tcpd = Rc::new(RefCell::new(Tcpd::new(scheme_file, tcp_file)));
let mut event_queue = EventQueue::<()>::new().expect("tcpd: failed to create event queue");
let tcp_tcpd = tcpd.clone();
event_queue.add(tcp_fd, move |_count: usize| -> io::Result<Option<()>> {
tcp_tcpd.borrow_mut().tcp_event()?;
Ok(None)
}).expect("tcpd: failed to listen to events on ip:6");
event_queue.add(scheme_fd, move |_count: usize| -> io::Result<Option<()>> {
tcpd.borrow_mut().scheme_event()?;
Ok(None)
}).expect("tcpd: failed to listen to events on :tcp");
event_queue.trigger_all(0).expect("tcpd: failed to trigger event queue");
event_queue.run().expect("tcpd: failed to run event queue");
});
}

View file

@ -1,328 +0,0 @@
use std::{cmp, mem};
use std::cell::UnsafeCell;
use std::sync::Arc;
use netutils::{n16, n32, Ipv4Addr, Checksum, Tcp, TcpHeader, TCP_SYN, TCP_PSH, TCP_FIN, TCP_ACK};
use resource_scheme::Resource;
use syscall;
use syscall::error::*;
pub struct TcpStream {
pub ip: usize,
pub host_addr: Ipv4Addr,
pub peer_addr: Ipv4Addr,
pub peer_port: u16,
pub host_port: u16,
pub sequence: u32,
pub acknowledge: u32,
pub finished: bool
}
impl TcpStream {
fn path(&self, buf: &mut [u8]) -> Result<usize> {
let path_string = format!("tcp:{}:{}/{}", self.peer_addr.to_string(), self.peer_port, self.host_port);
let path = path_string.as_bytes();
for (b, p) in buf.iter_mut().zip(path.iter()) {
*b = *p;
}
Ok(cmp::min(buf.len(), path.len()))
}
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
if self.finished {
return Ok(0);
}
loop {
let mut bytes = [0; 65536];
let count = try!(syscall::read(self.ip, &mut bytes));
if let Some(segment) = Tcp::from_bytes(&bytes[..count]) {
if segment.header.dst.get() == self.host_port && segment.header.src.get() == self.peer_port {
//println!("Read: {}=={} {:X}: {}", segment.header.sequence.get(), self.acknowledge, segment.header.flags.get(), segment.data.len());
if self.acknowledge == segment.header.sequence.get() {
if segment.header.flags.get() & TCP_FIN == TCP_FIN {
self.finished = true;
}
if segment.header.flags.get() & (TCP_SYN | TCP_ACK) == TCP_ACK {
let flags = if self.finished {
TCP_ACK | TCP_FIN
} else {
TCP_ACK
};
// Send ACK
self.acknowledge += segment.data.len() as u32;
let mut tcp = Tcp {
header: TcpHeader {
src: n16::new(self.host_port),
dst: n16::new(self.peer_port),
sequence: n32::new(self.sequence),
ack_num: n32::new(self.acknowledge),
flags: n16::new(((mem::size_of::<TcpHeader>() << 10) & 0xF000) as u16 | flags),
window_size: n16::new(65535),
checksum: Checksum {
data: 0
},
urgent_pointer: n16::new(0)
},
options: Vec::new(),
data: Vec::new()
};
tcp.checksum(&self.host_addr, &self.peer_addr);
//println!("Sending read ack: {} {} {:X}", tcp.header.sequence.get(), tcp.header.ack_num.get(), tcp.header.flags.get());
let _ = syscall::write(self.ip, &tcp.to_bytes());
// TODO: Support broken packets (one packet in two buffers)
let mut i = 0;
while i < buf.len() && i < segment.data.len() {
buf[i] = segment.data[i];
i += 1;
}
return Ok(i);
}
} else {
println!("TCP: MISMATCH: {}=={}", segment.header.sequence.get(), self.acknowledge);
}
} else {
println!("TCP: WRONG PORT {}=={} && {}=={}", segment.header.dst.get(), self.host_port, segment.header.src.get(), self.peer_port);
}
}
}
}
fn write(&mut self, buf: &[u8]) -> Result<usize> {
let tcp_data = Vec::from(buf);
let mut tcp = Tcp {
header: TcpHeader {
src: n16::new(self.host_port),
dst: n16::new(self.peer_port),
sequence: n32::new(self.sequence),
ack_num: n32::new(self.acknowledge),
flags: n16::new((((mem::size_of::<TcpHeader>()) << 10) & 0xF000) as u16 | TCP_PSH |
TCP_ACK),
window_size: n16::new(65535),
checksum: Checksum { data: 0 },
urgent_pointer: n16::new(0),
},
options: Vec::new(),
data: tcp_data,
};
tcp.checksum(&self.host_addr, &self.peer_addr);
match syscall::write(self.ip, &tcp.to_bytes()) {
Ok(size) => {
loop {
// Wait for ACK
let mut bytes = [0; 65536];
match syscall::read(self.ip, &mut bytes) {
Ok(count) => {
if let Some(segment) = Tcp::from_bytes(&bytes[..count]) {
if segment.header.dst.get() == self.host_port &&
segment.header.src.get() == self.peer_port {
return if (segment.header.flags.get() & (TCP_SYN | TCP_ACK)) == TCP_ACK {
self.sequence = segment.header.ack_num.get();
self.acknowledge = segment.header.sequence.get();
Ok(size)
} else {
Err(Error::new(EPIPE))
};
}
}
}
Err(err) => return Err(err),
}
}
}
Err(err) => Err(err),
}
}
fn sync(&mut self) -> Result<usize> {
syscall::fsync(self.ip)
}
/// Etablish client
pub fn client_establish(&mut self) -> bool {
// Send SYN
let mut tcp = Tcp {
header: TcpHeader {
src: n16::new(self.host_port),
dst: n16::new(self.peer_port),
sequence: n32::new(self.sequence),
ack_num: n32::new(self.acknowledge),
flags: n16::new(((mem::size_of::<TcpHeader>() << 10) & 0xF000) as u16 | TCP_SYN),
window_size: n16::new(65535),
checksum: Checksum { data: 0 },
urgent_pointer: n16::new(0),
},
options: Vec::new(),
data: Vec::new(),
};
tcp.checksum(&self.host_addr, &self.peer_addr);
match syscall::write(self.ip, &tcp.to_bytes()) {
Ok(_) => {
loop {
// Wait for SYN-ACK
let mut bytes = [0; 65536];
match syscall::read(self.ip, &mut bytes) {
Ok(count) => {
if let Some(segment) = Tcp::from_bytes(&bytes[..count]) {
if segment.header.dst.get() == self.host_port &&
segment.header.src.get() == self.peer_port {
return if segment.header.flags.get() & (TCP_SYN | TCP_ACK) == TCP_SYN | TCP_ACK {
self.sequence = segment.header.ack_num.get();
self.acknowledge = segment.header.sequence.get();
self.acknowledge += 1;
tcp = Tcp {
header: TcpHeader {
src: n16::new(self.host_port),
dst: n16::new(self.peer_port),
sequence: n32::new(self.sequence),
ack_num: n32::new(self.acknowledge),
flags: n16::new(((mem::size_of::<TcpHeader>() << 10) & 0xF000) as u16 | TCP_ACK),
window_size: n16::new(65535),
checksum: Checksum {
data: 0
},
urgent_pointer: n16::new(0)
},
options: Vec::new(),
data: Vec::new()
};
tcp.checksum(&self.host_addr, &self.peer_addr);
let _ = syscall::write(self.ip, &tcp.to_bytes());
true
} else {
false
};
}
}
}
Err(_) => return false,
}
}
}
Err(_) => false,
}
}
/// Try to establish a server connection
pub fn server_establish(&mut self, _: Tcp) -> bool {
// Send SYN-ACK
self.acknowledge += 1;
let mut tcp = Tcp {
header: TcpHeader {
src: n16::new(self.host_port),
dst: n16::new(self.peer_port),
sequence: n32::new(self.sequence),
ack_num: n32::new(self.acknowledge),
flags: n16::new(((mem::size_of::<TcpHeader>() << 10) & 0xF000) as u16 | TCP_SYN |
TCP_ACK),
window_size: n16::new(65535),
checksum: Checksum { data: 0 },
urgent_pointer: n16::new(0),
},
options: Vec::new(),
data: Vec::new(),
};
tcp.checksum(&self.host_addr, &self.peer_addr);
match syscall::write(self.ip, &tcp.to_bytes()) {
Ok(_) => {
loop {
// Wait for ACK
let mut bytes = [0; 65536];
match syscall::read(self.ip, &mut bytes) {
Ok(count ) => {
if let Some(segment) = Tcp::from_bytes(&bytes[..count]) {
if segment.header.dst.get() == self.host_port &&
segment.header.src.get() == self.peer_port {
return if segment.header.flags.get() & (TCP_SYN | TCP_ACK) == TCP_ACK {
self.sequence = segment.header.ack_num.get();
self.acknowledge = segment.header.sequence.get();
true
} else {
false
};
}
}
}
Err(_) => return false,
}
}
}
Err(_) => false,
}
}
}
impl Drop for TcpStream {
fn drop(&mut self) {
// Send FIN-ACK
let mut tcp = Tcp {
header: TcpHeader {
src: n16::new(self.host_port),
dst: n16::new(self.peer_port),
sequence: n32::new(self.sequence),
ack_num: n32::new(self.acknowledge),
flags: n16::new((((mem::size_of::<TcpHeader>()) << 10) & 0xF000) as u16 | TCP_FIN | TCP_ACK),
window_size: n16::new(65535),
checksum: Checksum { data: 0 },
urgent_pointer: n16::new(0),
},
options: Vec::new(),
data: Vec::new(),
};
tcp.checksum(&self.host_addr, &self.peer_addr);
let _ = syscall::write(self.ip, &tcp.to_bytes());
let _ = syscall::close(self.ip);
}
}
/// A TCP resource
pub struct TcpResource {
pub stream: Arc<UnsafeCell<TcpStream>>
}
impl Resource for TcpResource {
fn dup(&self) -> Result<Box<TcpResource>> {
Ok(Box::new(TcpResource {
stream: self.stream.clone()
}))
}
fn path(&self, buf: &mut [u8]) -> Result<usize> {
unsafe { (*self.stream.get()).path(buf) }
}
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
unsafe { (*self.stream.get()).read(buf) }
}
fn write(&mut self, buf: &[u8]) -> Result<usize> {
unsafe { (*self.stream.get()).write(buf) }
}
fn sync(&mut self) -> Result<usize> {
unsafe { (*self.stream.get()).sync() }
}
}

View file

@ -1,98 +0,0 @@
use std::cell::UnsafeCell;
use std::rand;
use std::sync::Arc;
use std::{str, u16};
use netutils::{getcfg, Ipv4Addr, Tcp, TCP_SYN, TCP_ACK};
use resource_scheme::ResourceScheme;
use syscall;
use syscall::error::{Error, Result, ENOENT, EINVAL};
use syscall::flag::O_RDWR;
use resource::{TcpResource, TcpStream};
/// A TCP scheme
pub struct TcpScheme;
impl ResourceScheme<TcpResource> for TcpScheme {
fn open_resource(&self, url: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result<Box<TcpResource>> {
let ip_addr = Ipv4Addr::from_str(&getcfg("ip").map_err(|err| err.into_sys())?);
let path = try!(str::from_utf8(url).or(Err(Error::new(EINVAL))));
let mut parts = path.split('/');
let remote = parts.next().unwrap_or("");
let path = parts.next().unwrap_or("");
let mut remote_parts = remote.split(':');
let host = remote_parts.next().unwrap_or("");
let port = remote_parts.next().unwrap_or("");
if ! host.is_empty() && ! port.is_empty() {
let peer_addr = Ipv4Addr::from_str(host);
let peer_port = port.parse::<u16>().unwrap_or(0);
let host_port = (rand() % 32768 + 32768) as u16;
match syscall::open(&format!("ip:{}/6", peer_addr.to_string()), O_RDWR) {
Ok(ip) => {
let mut stream = TcpStream {
ip: ip,
host_addr: ip_addr,
peer_addr: peer_addr,
peer_port: peer_port,
host_port: host_port,
sequence: rand() as u32,
acknowledge: 0,
finished: false
};
if stream.client_establish() {
return Ok(Box::new(TcpResource {
stream: Arc::new(UnsafeCell::new(stream))
}));
}
}
Err(err) => return Err(err),
}
} else if ! path.is_empty() {
let host_port = path.parse::<u16>().unwrap_or(0);
while let Ok(ip) = syscall::open("ip:/6", O_RDWR) {
let mut bytes = [0; 65536];
match syscall::read(ip, &mut bytes) {
Ok(count) => {
if let Some(segment) = Tcp::from_bytes(&bytes[..count]) {
if segment.header.dst.get() == host_port && segment.header.flags.get() & (TCP_SYN | TCP_ACK) == TCP_SYN {
let mut path = [0; 256];
if let Ok(path_count) = syscall::fpath(ip, &mut path) {
let ip_reference = unsafe { str::from_utf8_unchecked(&path[.. path_count]) }.split(':').nth(1).unwrap_or("");
let ip_remote = ip_reference.split('/').next().unwrap_or("");
let peer_addr = ip_remote.split(':').next().unwrap_or("");
let mut stream = TcpStream {
ip: ip,
host_addr: ip_addr,
peer_addr: Ipv4Addr::from_str(peer_addr),
peer_port: segment.header.src.get(),
host_port: host_port,
sequence: rand() as u32,
acknowledge: segment.header.sequence.get(),
finished: false
};
if stream.server_establish(segment) {
return Ok(Box::new(TcpResource {
stream: Arc::new(UnsafeCell::new(stream))
}));
}
}
}
}
}
Err(err) => return Err(err),
}
}
}
Err(Error::new(ENOENT))
}
}

View file

@ -3,6 +3,7 @@ name = "udpd"
version = "0.1.0"
[dependencies]
event = { path = "../../crates/event/" }
netutils = { path = "../../programs/netutils/" }
resource_scheme = { path = "../../crates/resource_scheme/" }
rand = { git = "https://github.com/redox-os/rand.git" }
syscall = { path = "../../syscall/" }

View file

@ -1,30 +1,348 @@
#![feature(rand)]
extern crate event;
extern crate netutils;
extern crate resource_scheme;
extern crate rand;
extern crate syscall;
use rand::{Rng, OsRng};
use std::collections::{BTreeMap, VecDeque};
use std::cell::RefCell;
use std::fs::File;
use std::io::{Read, Write};
use std::thread;
use std::io::{self, Read, Write};
use std::{mem, slice, str, thread};
use std::os::unix::io::FromRawFd;
use std::rc::Rc;
use resource_scheme::ResourceScheme;
use syscall::Packet;
use event::EventQueue;
use netutils::{n16, Ipv4, Ipv4Addr, Ipv4Header, Udp, UdpHeader, Checksum};
use syscall::data::Packet;
use syscall::error::{Error, Result, EACCES, EADDRINUSE, EBADF, EINVAL, EMSGSIZE, ENOTCONN, EWOULDBLOCK};
use syscall::flag::{EVENT_READ, O_CREAT, O_RDWR, O_NONBLOCK};
use syscall::scheme::SchemeMut;
use scheme::UdpScheme;
fn parse_socket(socket: &str) -> (Ipv4Addr, u16) {
let mut socket_parts = socket.split(":");
let host = Ipv4Addr::from_str(socket_parts.next().unwrap_or(""));
let port = socket_parts.next().unwrap_or("").parse::<u16>().unwrap_or(0);
(host, port)
}
mod resource;
mod scheme;
struct Handle {
local: (Ipv4Addr, u16),
remote: (Ipv4Addr, u16),
flags: usize,
events: usize,
data: VecDeque<Vec<u8>>,
todo: VecDeque<Packet>,
}
struct Udpd {
scheme_file: File,
udp_file: File,
ports: BTreeMap<u16, usize>,
next_id: usize,
handles: BTreeMap<usize, Handle>,
rng: OsRng,
}
impl Udpd {
fn new(scheme_file: File, udp_file: File) -> Self {
Udpd {
scheme_file: scheme_file,
udp_file: udp_file,
ports: BTreeMap::new(),
next_id: 1,
handles: BTreeMap::new(),
rng: OsRng::new().expect("udpd: failed to open RNG")
}
}
fn scheme_event(&mut self) -> io::Result<()> {
loop {
let mut packet = Packet::default();
if self.scheme_file.read(&mut packet)? == 0 {
break;
}
let a = packet.a;
self.handle(&mut packet);
if packet.a == (-EWOULDBLOCK) as usize {
packet.a = a;
if let Some(mut handle) = self.handles.get_mut(&packet.b) {
handle.todo.push_back(packet);
}
} else {
self.scheme_file.write(&packet)?;
}
}
Ok(())
}
fn udp_event(&mut self) -> io::Result<()> {
loop {
let mut bytes = [0; 65536];
let count = self.udp_file.read(&mut bytes)?;
if count == 0 {
break;
}
if let Some(ip) = Ipv4::from_bytes(&bytes[.. count]) {
if let Some(udp) = Udp::from_bytes(&ip.data) {
for (id, handle) in self.handles.iter_mut() {
// Local address not set or IP dst matches or is broadcast
if (handle.local.0 == Ipv4Addr::NULL || ip.header.dst == handle.local.0 || ip.header.dst == Ipv4Addr::BROADCAST)
// Local port matches UDP dst
&& udp.header.dst.get() == handle.local.1
// Remote address not set or is broadcast, or IP src matches
&& (handle.remote.0 == Ipv4Addr::NULL || handle.remote.0 == Ipv4Addr::BROADCAST || ip.header.src == handle.remote.0)
// Remote port not set or UDP src matches
&& (handle.remote.1 == 0 || udp.header.src.get() == handle.remote.1)
{
handle.data.push_back(udp.data.clone());
while ! handle.todo.is_empty() && ! handle.data.is_empty() {
let mut packet = handle.todo.pop_front().unwrap();
let buf = unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) };
let data = handle.data.pop_front().unwrap();
let mut i = 0;
while i < buf.len() && i < data.len() {
buf[i] = data[i];
i += 1;
}
packet.a = i;
self.scheme_file.write(&packet)?;
}
if handle.events & EVENT_READ == EVENT_READ {
if let Some(data) = handle.data.get(0) {
self.scheme_file.write(&Packet {
id: 0,
pid: 0,
uid: 0,
gid: 0,
a: syscall::number::SYS_FEVENT,
b: *id,
c: EVENT_READ,
d: data.len()
})?;
}
}
}
}
}
}
}
Ok(())
}
}
impl SchemeMut for Udpd {
fn open(&mut self, url: &[u8], flags: usize, uid: u32, _gid: u32) -> Result<usize> {
let path = str::from_utf8(url).or(Err(Error::new(EINVAL)))?;
let mut parts = path.split("/");
let remote = parse_socket(parts.next().unwrap_or(""));
let mut local = parse_socket(parts.next().unwrap_or(""));
if local.1 == 0 {
local.1 = self.rng.gen_range(32768, 65535);
}
if local.1 <= 1024 && uid != 0 {
return Err(Error::new(EACCES));
}
if self.ports.contains_key(&local.1) {
return Err(Error::new(EADDRINUSE));
}
self.ports.insert(local.1, 1);
let id = self.next_id;
self.next_id += 1;
self.handles.insert(id, Handle {
local: local,
remote: remote,
flags: flags,
events: 0,
data: VecDeque::new(),
todo: VecDeque::new(),
});
Ok(id)
}
fn dup(&mut self, file: usize, buf: &[u8]) -> Result<usize> {
let mut handle = {
let handle = self.handles.get(&file).ok_or(Error::new(EBADF))?;
Handle {
local: handle.local,
remote: handle.remote,
flags: handle.flags,
events: 0,
data: handle.data.clone(),
todo: VecDeque::new(),
}
};
let path = str::from_utf8(buf).or(Err(Error::new(EINVAL)))?;
if handle.remote.0 == Ipv4Addr::NULL || handle.remote.1 == 0 {
handle.remote = parse_socket(path);
}
if let Some(mut port) = self.ports.get_mut(&handle.local.1) {
*port = *port + 1;
}
let id = self.next_id;
self.next_id += 1;
self.handles.insert(id, handle);
Ok(id)
}
fn read(&mut self, file: usize, buf: &mut [u8]) -> Result<usize> {
let mut handle = self.handles.get_mut(&file).ok_or(Error::new(EBADF))?;
if handle.remote.0 == Ipv4Addr::NULL || handle.remote.1 == 0 {
Err(Error::new(ENOTCONN))
} else if let Some(data) = handle.data.pop_front() {
let mut i = 0;
while i < buf.len() && i < data.len() {
buf[i] = data[i];
i += 1;
}
Ok(i)
} else if handle.flags & O_NONBLOCK == O_NONBLOCK {
Ok(0)
} else {
Err(Error::new(EWOULDBLOCK))
}
}
fn write(&mut self, file: usize, buf: &[u8]) -> Result<usize> {
let handle = self.handles.get(&file).ok_or(Error::new(EBADF))?;
if handle.remote.0 == Ipv4Addr::NULL || handle.remote.1 == 0 {
Err(Error::new(ENOTCONN))
} else if buf.len() >= 65507 {
Err(Error::new(EMSGSIZE))
} else {
let udp_data = buf.to_vec();
let udp = Udp {
header: UdpHeader {
src: n16::new(handle.local.1),
dst: n16::new(handle.remote.1),
len: n16::new((udp_data.len() + mem::size_of::<UdpHeader>()) as u16),
checksum: Checksum { data: 0 }
},
data: udp_data
};
let ip_data = udp.to_bytes();
let ip = Ipv4 {
header: Ipv4Header {
ver_hlen: 0x45,
services: 0,
len: n16::new((ip_data.len() + mem::size_of::<Ipv4Header>()) as u16),
id: n16::new(self.rng.gen()),
flags_fragment: n16::new(0),
ttl: 127,
proto: 0x11,
checksum: Checksum { data: 0 },
src: handle.local.0,
dst: handle.remote.0
},
options: Vec::new(),
data: ip_data
};
self.udp_file.write(&ip.to_bytes()).map_err(|err| err.into_sys()).and(Ok(buf.len()))
}
}
fn fevent(&mut self, file: usize, flags: usize) -> Result<usize> {
let mut handle = self.handles.get_mut(&file).ok_or(Error::new(EBADF))?;
handle.events = flags;
Ok(file)
}
fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result<usize> {
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
let path_string = format!("udp:{}:{}/{}:{}", handle.remote.0.to_string(), handle.remote.1, handle.local.0.to_string(), handle.local.1);
let path = path_string.as_bytes();
let mut i = 0;
while i < buf.len() && i < path.len() {
buf[i] = path[i];
i += 1;
}
Ok(i)
}
fn fsync(&mut self, file: usize) -> Result<usize> {
let _handle = self.handles.get(&file).ok_or(Error::new(EBADF))?;
Ok(0)
}
fn close(&mut self, file: usize) -> Result<usize> {
let handle = self.handles.remove(&file).ok_or(Error::new(EBADF))?;
let remove = if let Some(mut port) = self.ports.get_mut(&handle.local.1) {
*port = *port + 1;
*port == 0
} else {
false
};
if remove {
drop(self.ports.remove(&handle.local.1));
}
drop(handle);
Ok(0)
}
}
fn main() {
thread::spawn(move || {
let mut socket = File::create(":udp").expect("udpd: failed to create udp scheme");
let scheme = UdpScheme;
loop {
let mut packet = Packet::default();
socket.read(&mut packet).expect("udpd: failed to read events from udp scheme");
scheme.handle(&mut packet);
socket.write(&packet).expect("udpd: failed to write responses to udp scheme");
}
let scheme_fd = syscall::open(":udp", O_RDWR | O_CREAT | O_NONBLOCK).expect("udpd: failed to create :udp");
let scheme_file = unsafe { File::from_raw_fd(scheme_fd) };
let udp_fd = syscall::open("ip:11", O_RDWR | O_NONBLOCK).expect("udpd: failed to open ip:11");
let udp_file = unsafe { File::from_raw_fd(udp_fd) };
let udpd = Rc::new(RefCell::new(Udpd::new(scheme_file, udp_file)));
let mut event_queue = EventQueue::<()>::new().expect("udpd: failed to create event queue");
let udp_udpd = udpd.clone();
event_queue.add(udp_fd, move |_count: usize| -> io::Result<Option<()>> {
udp_udpd.borrow_mut().udp_event()?;
Ok(None)
}).expect("udpd: failed to listen to events on ip:11");
event_queue.add(scheme_fd, move |_count: usize| -> io::Result<Option<()>> {
udpd.borrow_mut().scheme_event()?;
Ok(None)
}).expect("udpd: failed to listen to events on :udp");
event_queue.trigger_all(0).expect("udpd: failed to trigger event queue");
event_queue.run().expect("udpd: failed to run event queue");
});
}

View file

@ -1,115 +0,0 @@
use std::{cmp, mem};
use netutils::{n16, Ipv4Addr, Checksum, Udp, UdpHeader};
use resource_scheme::Resource;
use syscall;
use syscall::error::*;
/// UDP resource
pub struct UdpResource {
pub ip: usize,
pub data: Vec<u8>,
pub host_addr: Ipv4Addr,
pub peer_addr: Ipv4Addr,
pub peer_port: u16,
pub host_port: u16,
}
impl Resource for UdpResource {
fn dup(&self) -> Result<Box<UdpResource>> {
match syscall::dup(self.ip) {
Ok(ip) => {
Ok(Box::new(UdpResource {
ip: ip,
data: self.data.clone(),
host_addr: self.host_addr,
peer_addr: self.peer_addr,
peer_port: self.peer_port,
host_port: self.host_port,
}))
}
Err(err) => Err(err),
}
}
fn path(&self, buf: &mut [u8]) -> Result<usize> {
let path_string = format!("udp:{}:{}/{}", self.peer_addr.to_string(), self.peer_port, self.host_port);
let path = path_string.as_bytes();
for (b, p) in buf.iter_mut().zip(path.iter()) {
*b = *p;
}
Ok(cmp::min(buf.len(), path.len()))
}
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
if ! self.data.is_empty() {
let mut bytes: Vec<u8> = Vec::new();
mem::swap(&mut self.data, &mut bytes);
// TODO: Allow splitting
let mut i = 0;
while i < buf.len() && i < bytes.len() {
buf[i] = bytes[i];
i += 1;
}
return Ok(i);
}
loop {
let mut bytes = [0; 65536];
let count = try!(syscall::read(self.ip, &mut bytes));
if let Some(datagram) = Udp::from_bytes(&bytes[..count]) {
if datagram.header.dst.get() == self.host_port &&
datagram.header.src.get() == self.peer_port {
// TODO: Allow splitting
let mut i = 0;
while i < buf.len() && i < datagram.data.len() {
buf[i] = datagram.data[i];
i += 1;
}
return Ok(i);
}
}
}
}
fn write(&mut self, buf: &[u8]) -> Result<usize> {
let mut udp = Udp {
header: UdpHeader {
src: n16::new(self.host_port),
dst: n16::new(self.peer_port),
len: n16::new((mem::size_of::<UdpHeader>() + buf.len()) as u16),
checksum: Checksum { data: 0 },
},
data: Vec::from(buf),
};
unsafe {
let proto = n16::new(0x11);
let datagram_len = n16::new((mem::size_of::<UdpHeader>() + udp.data.len()) as u16);
udp.header.checksum.data =
Checksum::compile(Checksum::sum((&self.host_addr as *const Ipv4Addr) as usize,
mem::size_of::<Ipv4Addr>()) +
Checksum::sum((&self.peer_addr as *const Ipv4Addr) as usize,
mem::size_of::<Ipv4Addr>()) +
Checksum::sum((&proto as *const n16) as usize,
mem::size_of::<n16>()) +
Checksum::sum((&datagram_len as *const n16) as usize,
mem::size_of::<n16>()) +
Checksum::sum((&udp.header as *const UdpHeader) as usize,
mem::size_of::<UdpHeader>()) +
Checksum::sum(udp.data.as_ptr() as usize, udp.data.len()));
}
syscall::write(self.ip, &udp.to_bytes()).and(Ok(buf.len()))
}
fn sync(&mut self) -> Result<usize> {
syscall::fsync(self.ip)
}
}

View file

@ -1,73 +0,0 @@
use std::rand;
use std::{str, u16};
use netutils::{getcfg, Ipv4Addr, Udp};
use resource_scheme::ResourceScheme;
use syscall;
use syscall::error::{Error, Result, ENOENT, EINVAL};
use syscall::flag::O_RDWR;
use resource::UdpResource;
/// UDP UdpScheme
pub struct UdpScheme;
impl ResourceScheme<UdpResource> for UdpScheme {
fn open_resource(&self, url: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result<Box<UdpResource>> {
let ip_addr = Ipv4Addr::from_str(&getcfg("ip").map_err(|err| err.into_sys())?);
let path = try!(str::from_utf8(url).or(Err(Error::new(EINVAL))));
let mut parts = path.split('/');
let remote = parts.next().unwrap_or("");
let path = parts.next().unwrap_or("");
// Check host and port vs path
if remote.is_empty() {
let host_port = path.parse::<u16>().unwrap_or(0);
if host_port > 0 {
while let Ok(ip) = syscall::open("ip:/11", O_RDWR) {
let mut bytes = [0; 65536];
if let Ok(count) = syscall::read(ip, &mut bytes) {
if let Some(datagram) = Udp::from_bytes(&bytes[..count]) {
if datagram.header.dst.get() == host_port {
let mut path = [0; 256];
if let Ok(path_count) = syscall::fpath(ip, &mut path) {
let ip_reference = unsafe { str::from_utf8_unchecked(&path[.. path_count]) }.split(':').nth(1).unwrap_or("");
let peer_addr = ip_reference.split('/').next().unwrap_or("").split(':').next().unwrap_or("");
return Ok(Box::new(UdpResource {
ip: ip,
data: datagram.data,
host_addr: ip_addr,
peer_addr: Ipv4Addr::from_str(peer_addr),
peer_port: datagram.header.src.get(),
host_port: host_port,
}));
}
}
}
}
}
}
} else {
let mut remote_parts = remote.split(':');
let peer_addr = remote_parts.next().unwrap_or("");
let peer_port = remote_parts.next().unwrap_or("").parse::<u16>().unwrap_or(0);
if peer_port > 0 {
let host_port = path.parse::<u16>().unwrap_or((rand() % 32768 + 32768) as u16);
if let Ok(ip) = syscall::open(&format!("ip:{}/11", peer_addr), O_RDWR) {
return Ok(Box::new(UdpResource {
ip: ip,
data: Vec::new(),
host_addr: ip_addr,
peer_addr: Ipv4Addr::from_str(peer_addr),
peer_port: peer_port as u16,
host_port: host_port,
}));
}
}
}
Err(Error::new(ENOENT))
}
}

View file

@ -48,8 +48,8 @@ pub fn clock_gettime(clock: usize, tp: &mut TimeSpec) -> Result<usize> {
unsafe { syscall2(SYS_CLOCK_GETTIME, clock, tp as *mut TimeSpec as usize) }
}
pub fn dup(fd: usize) -> Result<usize> {
unsafe { syscall1(SYS_DUP, fd) }
pub fn dup(fd: usize, buf: &[u8]) -> Result<usize> {
unsafe { syscall3(SYS_DUP, fd, buf.as_ptr() as usize, buf.len()) }
}
pub fn execve(path: &str, args: &[[usize; 2]]) -> Result<usize> {

View file

@ -10,7 +10,7 @@ pub trait Scheme {
SYS_RMDIR => self.rmdir(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }, packet.uid, packet.gid),
SYS_UNLINK => self.unlink(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }, packet.uid, packet.gid),
SYS_DUP => self.dup(packet.b),
SYS_DUP => self.dup(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }),
SYS_READ => self.read(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }),
SYS_WRITE => self.write(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }),
SYS_LSEEK => self.seek(packet.b, packet.c, packet.d),
@ -49,7 +49,7 @@ pub trait Scheme {
/* Resource operations */
#[allow(unused_variables)]
fn dup(&self, old_id: usize) -> Result<usize> {
fn dup(&self, old_id: usize, buf: &[u8]) -> Result<usize> {
Err(Error::new(EBADF))
}
@ -107,7 +107,7 @@ pub trait SchemeMut {
SYS_RMDIR => self.rmdir(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }, packet.uid, packet.gid),
SYS_UNLINK => self.unlink(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }, packet.uid, packet.gid),
SYS_DUP => self.dup(packet.b),
SYS_DUP => self.dup(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }),
SYS_READ => self.read(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }),
SYS_WRITE => self.write(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }),
SYS_LSEEK => self.seek(packet.b, packet.c, packet.d),
@ -145,7 +145,7 @@ pub trait SchemeMut {
/* Resource operations */
#[allow(unused_variables)]
fn dup(&mut self, old_id: usize) -> Result<usize> {
fn dup(&mut self, old_id: usize, buf: &[u8]) -> Result<usize> {
Err(Error::new(EBADF))
}