diff --git a/Makefile b/Makefile index 191559f..7012007 100644 --- a/Makefile +++ b/Makefile @@ -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 \ diff --git a/arch/x86_64/src/acpi/dmar.rs b/arch/x86_64/src/acpi/dmar.rs new file mode 100644 index 0000000..99dff90 --- /dev/null +++ b/arch/x86_64/src/acpi/dmar.rs @@ -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 { + 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 { + 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::() { + DmarEntry::Drhd(unsafe { &*((self.sdt.data_address() + self.i) as *const DmarDrhd) }) + } else { + DmarEntry::InvalidDrhd(entry_len) + }, + 1 => if entry_len >= mem::size_of::() { + DmarEntry::Rmrr(unsafe { &*((self.sdt.data_address() + self.i) as *const DmarRmrr) }) + } else { + DmarEntry::InvalidRmrr(entry_len) + }, + 2 => if entry_len >= mem::size_of::() { + DmarEntry::Atsr(unsafe { &*((self.sdt.data_address() + self.i) as *const DmarAtsr) }) + } else { + DmarEntry::InvalidAtsr(entry_len) + }, + 3 => if entry_len == mem::size_of::() { + DmarEntry::Rhsa(unsafe { &*((self.sdt.data_address() + self.i) as *const DmarRhsa) }) + } else { + DmarEntry::InvalidRhsa(entry_len) + }, + 4 => if entry_len >= mem::size_of::() { + 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 + } + } +} diff --git a/arch/x86_64/src/acpi/mod.rs b/arch/x86_64/src/acpi/mod.rs index 57d3245..dd94fab 100644 --- a/arch/x86_64/src/acpi/mod.rs +++ b/arch/x86_64/src/acpi/mod.rs @@ -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"); } diff --git a/crates/event/src/lib.rs b/crates/event/src/lib.rs index 965f2e9..18fabbf 100644 --- a/crates/event/src/lib.rs +++ b/crates/event/src/lib.rs @@ -38,13 +38,43 @@ impl EventQueue { Ok(()) } + /// Remove a file from the event queue, returning its callback if found + pub fn remove(&mut self, fd: RawFd) -> Result Result>>>> { + 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> { + 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> { + 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 { 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); } } diff --git a/crates/resource_scheme/src/resource.rs b/crates/resource_scheme/src/resource.rs index cf2fe5c..0f23183 100644 --- a/crates/resource_scheme/src/resource.rs +++ b/crates/resource_scheme/src/resource.rs @@ -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> { + fn dup(&self, _buf: &[u8]) -> Result> { Err(Error::new(EPERM)) } diff --git a/crates/resource_scheme/src/scheme.rs b/crates/resource_scheme/src/scheme.rs index 308f511..c484a94 100644 --- a/crates/resource_scheme/src/scheme.rs +++ b/crates/resource_scheme/src/scheme.rs @@ -16,7 +16,7 @@ pub trait ResourceScheme { 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 { } /* Resource operations */ - fn dup(&self, old_id: usize) -> Result { + fn dup(&self, old_id: usize, buf: &[u8]) -> Result { 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) } diff --git a/drivers/ahcid/src/main.rs b/drivers/ahcid/src/main.rs index e7aa816..02a5145 100644 --- a/drivers/ahcid/src/main.rs +++ b/drivers/ahcid/src/main.rs @@ -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() { diff --git a/drivers/ahcid/src/scheme.rs b/drivers/ahcid/src/scheme.rs index 790e920..96a7c20 100644 --- a/drivers/ahcid/src/scheme.rs +++ b/drivers/ahcid/src/scheme.rs @@ -47,7 +47,7 @@ impl Scheme for DiskScheme { } } - fn dup(&self, id: usize) -> Result { + fn dup(&self, id: usize, _buf: &[u8]) -> Result { let mut handles = self.handles.lock(); let new_handle = { let handle = handles.get(&id).ok_or(Error::new(EBADF))?; diff --git a/drivers/e1000d/src/device.rs b/drivers/e1000d/src/device.rs index 3501986..fe2df01 100644 --- a/drivers/e1000d/src/device.rs +++ b/drivers/e1000d/src/device.rs @@ -109,7 +109,7 @@ impl Scheme for Intel8254x { } } - fn dup(&self, id: usize) -> Result { + fn dup(&self, id: usize, _buf: &[u8]) -> Result { Ok(id) } diff --git a/drivers/e1000d/src/main.rs b/drivers/e1000d/src/main.rs index ee721ee..90f2590 100644 --- a/drivers/e1000d/src/main.rs +++ b/drivers/e1000d/src/main.rs @@ -80,16 +80,20 @@ fn main() { let socket_packet = socket.clone(); event_queue.add(socket_fd, move |_count: usize| -> Result> { - 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); } diff --git a/drivers/ps2d/src/main.rs b/drivers/ps2d/src/main.rs index d1f1bff..ba5e330 100644 --- a/drivers/ps2d/src/main.rs +++ b/drivers/ps2d/src/main.rs @@ -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); } }); } diff --git a/drivers/rtl8168d/src/device.rs b/drivers/rtl8168d/src/device.rs index da2b2ee..923d888 100644 --- a/drivers/rtl8168d/src/device.rs +++ b/drivers/rtl8168d/src/device.rs @@ -84,7 +84,7 @@ impl SchemeMut for Rtl8168 { } } - fn dup(&mut self, id: usize) -> Result { + fn dup(&mut self, id: usize, _buf: &[u8]) -> Result { Ok(id) } diff --git a/drivers/rtl8168d/src/main.rs b/drivers/rtl8168d/src/main.rs index e6d5b62..ca441cd 100644 --- a/drivers/rtl8168d/src/main.rs +++ b/drivers/rtl8168d/src/main.rs @@ -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> { - 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); } diff --git a/drivers/vesad/src/main.rs b/drivers/vesad/src/main.rs index e1437e7..b9defbf 100644 --- a/drivers/vesad/src/main.rs +++ b/drivers/vesad/src/main.rs @@ -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) { diff --git a/drivers/vesad/src/scheme.rs b/drivers/vesad/src/scheme.rs index dd26e6a..c81f558 100644 --- a/drivers/vesad/src/scheme.rs +++ b/drivers/vesad/src/scheme.rs @@ -60,7 +60,7 @@ impl SchemeMut for DisplayScheme { } } - fn dup(&mut self, id: usize) -> Result { + fn dup(&mut self, id: usize, _buf: &[u8]) -> Result { Ok(id) } diff --git a/filesystem/etc/init.rc b/filesystem/etc/init.rc index 6df7d63..27ac5e9 100644 --- a/filesystem/etc/init.rc +++ b/filesystem/etc/init.rc @@ -1,7 +1,6 @@ randd initfs:bin/pcid /etc/pcid.toml ethernetd -arpd ipd tcpd udpd diff --git a/kernel/scheme/debug.rs b/kernel/scheme/debug.rs index 27ab626..8a8f556 100644 --- a/kernel/scheme/debug.rs +++ b/kernel/scheme/debug.rs @@ -33,7 +33,7 @@ impl Scheme for DebugScheme { Ok(0) } - fn dup(&self, _file: usize) -> Result { + fn dup(&self, _file: usize, _buf: &[u8]) -> Result { Ok(0) } diff --git a/kernel/scheme/env.rs b/kernel/scheme/env.rs index 4a51485..3c88b1e 100644 --- a/kernel/scheme/env.rs +++ b/kernel/scheme/env.rs @@ -88,7 +88,7 @@ impl Scheme for EnvScheme { } } - fn dup(&self, id: usize) -> Result { + fn dup(&self, id: usize, _buf: &[u8]) -> Result { let new_handle = { let handles = self.handles.read(); let handle = handles.get(&id).ok_or(Error::new(EBADF))?; diff --git a/kernel/scheme/event.rs b/kernel/scheme/event.rs index cca7420..2266141 100644 --- a/kernel/scheme/event.rs +++ b/kernel/scheme/event.rs @@ -39,7 +39,7 @@ impl Scheme for EventScheme { Ok(id) } - fn dup(&self, id: usize) -> Result { + fn dup(&self, id: usize, _buf: &[u8]) -> Result { let handle = { let handles = self.handles.read(); let handle_weak = handles.get(&id).ok_or(Error::new(EBADF))?; diff --git a/kernel/scheme/initfs.rs b/kernel/scheme/initfs.rs index 18696ed..99f1f7d 100644 --- a/kernel/scheme/initfs.rs +++ b/kernel/scheme/initfs.rs @@ -57,7 +57,7 @@ impl Scheme for InitFsScheme { Err(Error::new(ENOENT)) } - fn dup(&self, id: usize) -> Result { + fn dup(&self, id: usize, _buf: &[u8]) -> Result { let (path, data, mode, seek) = { let handles = self.handles.read(); let handle = handles.get(&id).ok_or(Error::new(EBADF))?; diff --git a/kernel/scheme/irq.rs b/kernel/scheme/irq.rs index f91118e..a20aca7 100644 --- a/kernel/scheme/irq.rs +++ b/kernel/scheme/irq.rs @@ -40,7 +40,7 @@ impl Scheme for IrqScheme { } } - fn dup(&self, file: usize) -> Result { + fn dup(&self, file: usize, _buf: &[u8]) -> Result { Ok(file) } diff --git a/kernel/scheme/pipe.rs b/kernel/scheme/pipe.rs index 35dfd00..49d4895 100644 --- a/kernel/scheme/pipe.rs +++ b/kernel/scheme/pipe.rs @@ -42,7 +42,7 @@ pub fn pipe(flags: usize) -> (usize, usize) { pub struct PipeScheme; impl Scheme for PipeScheme { - fn dup(&self, id: usize) -> Result { + fn dup(&self, id: usize, _buf: &[u8]) -> Result { let mut pipes = pipes_mut(); let read_option = pipes.0.get(&id).map(|pipe| pipe.clone()); diff --git a/kernel/scheme/root.rs b/kernel/scheme/root.rs index a253132..737e74b 100644 --- a/kernel/scheme/root.rs +++ b/kernel/scheme/root.rs @@ -56,7 +56,7 @@ impl Scheme for RootScheme { } } - fn dup(&self, file: usize) -> Result { + fn dup(&self, file: usize, _buf: &[u8]) -> Result { 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 { - Ok(file) + fn fevent(&self, file: usize, flags: usize) -> Result { + 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 { - Ok(0) + fn fsync(&self, file: usize) -> Result { + 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 { diff --git a/kernel/scheme/sys/mod.rs b/kernel/scheme/sys/mod.rs index 917b907..7d560d3 100644 --- a/kernel/scheme/sys/mod.rs +++ b/kernel/scheme/sys/mod.rs @@ -92,7 +92,7 @@ impl Scheme for SysScheme { Err(Error::new(ENOENT)) } - fn dup(&self, id: usize) -> Result { + fn dup(&self, id: usize, _buf: &[u8]) -> Result { let (path, data, mode, seek) = { let handles = self.handles.read(); let handle = handles.get(&id).ok_or(Error::new(EBADF))?; diff --git a/kernel/scheme/user.rs b/kernel/scheme/user.rs index 8f1c95a..2854821 100644 --- a/kernel/scheme/user.rs +++ b/kernel/scheme/user.rs @@ -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::()); - } + context::event::trigger(ROOT_SCHEME_ID.load(Ordering::SeqCst), self.handle_id, EVENT_READ, mem::size_of::() * len); Error::demux(self.done.receive(&id)) } @@ -182,6 +179,14 @@ impl UserInner { Ok(i * packet_size) } + + pub fn fevent(&self, _flags: usize) -> Result { + Ok(self.handle_id) + } + + pub fn fsync(&self) -> Result { + Ok(0) + } } /// UserInner has to be wrapped @@ -230,9 +235,12 @@ impl Scheme for UserScheme { result } - fn dup(&self, file: usize) -> Result { + fn dup(&self, file: usize, buf: &[u8]) -> Result { 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 { diff --git a/kernel/syscall/fs.rs b/kernel/syscall/fs.rs index 6c953e4..ff4a51d 100644 --- a/kernel/syscall/fs.rs +++ b/kernel/syscall/fs.rs @@ -83,10 +83,10 @@ pub fn open(path: &[u8], flags: usize) -> Result { 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 { 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 { 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 { 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 { } /// Duplicate file descriptor -pub fn dup(fd: usize) -> Result { +pub fn dup(fd: usize, buf: &[u8]) -> Result { 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 { 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(); diff --git a/kernel/syscall/mod.rs b/kernel/syscall/mod.rs index 8e1c190..2598cfa 100644 --- a/kernel/syscall/mod.rs +++ b/kernel/syscall/mod.rs @@ -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) } diff --git a/kernel/syscall/process.rs b/kernel/syscall/process.rs index 39dd822..e3cd886 100644 --- a/kernel/syscall/process.rs +++ b/kernel/syscall/process.rs @@ -227,7 +227,7 @@ pub fn clone(flags: usize, stack_base: usize) -> Result { 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 { diff --git a/libstd b/libstd index 4f642ee..a390903 160000 --- a/libstd +++ b/libstd @@ -1 +1 @@ -Subproject commit 4f642eed87af22913af7bef9c71910ee1765445e +Subproject commit a390903a03d7cebe448af803e635a46fa1609262 diff --git a/programs/acid b/programs/acid index 9faaf3a..1afcf7a 160000 --- a/programs/acid +++ b/programs/acid @@ -1 +1 @@ -Subproject commit 9faaf3a9690186a12da980fb877c8f05faea62aa +Subproject commit 1afcf7ab26ca3f697082674e6a72c94dd211c74b diff --git a/programs/netutils b/programs/netutils index 4eae543..6926b23 160000 --- a/programs/netutils +++ b/programs/netutils @@ -1 +1 @@ -Subproject commit 4eae543a60a5d6b0298db09bc48b2e6fab60b021 +Subproject commit 6926b235c47488f1bb2f5574a0445c7698e3ab99 diff --git a/programs/orbutils b/programs/orbutils index 517ca6d..78cd23b 160000 --- a/programs/orbutils +++ b/programs/orbutils @@ -1 +1 @@ -Subproject commit 517ca6d125e90d6b30e45a759f54b1d1b3b346d4 +Subproject commit 78cd23bf67adad79fb3e45ae4647055b01df026f diff --git a/schemes/arpd/Cargo.toml b/schemes/arpd/Cargo.toml deleted file mode 100644 index dfeff5f..0000000 --- a/schemes/arpd/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "arpd" -version = "0.1.0" - -[dependencies] -netutils = { path = "../../programs/netutils/" } -syscall = { path = "../../syscall/" } diff --git a/schemes/arpd/src/main.rs b/schemes/arpd/src/main.rs deleted file mode 100644 index ab2f6f1..0000000 --- a/schemes/arpd/src/main.rs +++ /dev/null @@ -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"); - }); -} diff --git a/schemes/ethernetd/src/main.rs b/schemes/ethernetd/src/main.rs index 13903f5..a238aee 100644 --- a/schemes/ethernetd/src/main.rs +++ b/schemes/ethernetd/src/main.rs @@ -68,21 +68,27 @@ fn main() { }).expect("ethernetd: failed to listen for network events"); event_queue.add(socket_fd, move |_count: usize| -> Result> { - 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"); }); } diff --git a/schemes/ethernetd/src/scheme.rs b/schemes/ethernetd/src/scheme.rs index 88b3f66..9dba500 100644 --- a/schemes/ethernetd/src/scheme.rs +++ b/schemes/ethernetd/src/scheme.rs @@ -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, /// 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 { - 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 { + fn open(&mut self, url: &[u8], flags: usize, uid: u32, _gid: u32) -> Result { 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 { + fn dup(&mut self, id: usize, _buf: &[u8]) -> Result { 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 { 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 { 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 { @@ -169,7 +156,9 @@ impl SchemeMut for EthernetScheme { fn close(&mut self, id: usize) -> Result { let handle = self.handles.remove(&id).ok_or(Error::new(EBADF))?; + drop(handle); + Ok(0) } } diff --git a/schemes/example/src/main.rs b/schemes/example/src/main.rs index 06ba194..94db5d1 100644 --- a/schemes/example/src/main.rs +++ b/schemes/example/src/main.rs @@ -15,7 +15,7 @@ impl Scheme for ExampleScheme { Ok(0) } - fn dup(&self, file: usize) -> Result { + fn dup(&self, file: usize, _buf: &[u8]) -> Result { Ok(file) } diff --git a/schemes/ipd/Cargo.toml b/schemes/ipd/Cargo.toml index b7359cb..e02660f 100644 --- a/schemes/ipd/Cargo.toml +++ b/schemes/ipd/Cargo.toml @@ -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/" } diff --git a/schemes/ipd/src/main.rs b/schemes/ipd/src/main.rs index de36d06..47b9a1f 100644 --- a/schemes/ipd/src/main.rs +++ b/schemes/ipd/src/main.rs @@ -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, + rarp: BTreeMap, +} -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>, + todo: VecDeque, +} + +struct Ipd { + scheme_file: File, + interfaces: Vec, + next_id: usize, + handles: BTreeMap, +} + +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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + let _handle = self.handles.get(&file).ok_or(Error::new(EBADF))?; + + Ok(0) + } + + fn close(&mut self, file: usize) -> Result { + 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> { + 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> { + 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> { + 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 = (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); - } -} \ No newline at end of file diff --git a/schemes/ipd/src/resource.rs b/schemes/ipd/src/resource.rs deleted file mode 100644 index 87ea11c..0000000 --- a/schemes/ipd/src/resource.rs +++ /dev/null @@ -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, - }, - 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>>> - } -} - -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> { - 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 { - 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 { - 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 = 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 { - 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::() / 4 & 0xF) as u8, // No Options - services: 0, - len: n16::new((mem::size_of::() + 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::()) + - 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 { - 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); - } - } -} diff --git a/schemes/ipd/src/scheme.rs b/schemes/ipd/src/scheme.rs deleted file mode 100644 index 8604e54..0000000 --- a/schemes/ipd/src/scheme.rs +++ /dev/null @@ -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>, - - /// 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>>>, -} - -impl IpScheme { - pub fn new() -> IpScheme { - IpScheme { - arp: RefCell::new(Vec::new()), - loopback_fifo: Rc::new(RefCell::new(VecDeque::new())), - } - } -} - -impl ResourceScheme for IpScheme { - fn open_resource(&self, url: &[u8], _flags: usize, uid: u32, _gid: u32) -> Result> { - 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)) - } - } -} diff --git a/schemes/orbital b/schemes/orbital index 601c568..1d554ed 160000 --- a/schemes/orbital +++ b/schemes/orbital @@ -1 +1 @@ -Subproject commit 601c5685f058c9276d896262195b50c75a6d7a97 +Subproject commit 1d554eda337b9d75a4c0b209c3b399b8f1148f35 diff --git a/schemes/randd/src/main.rs b/schemes/randd/src/main.rs index bafe051..5711601 100644 --- a/schemes/randd/src/main.rs +++ b/schemes/randd/src/main.rs @@ -16,7 +16,7 @@ impl Scheme for RandScheme { Ok(0) } - fn dup(&self, file: usize) -> Result { + fn dup(&self, file: usize, _buf: &[u8]) -> Result { Ok(file) } diff --git a/schemes/redoxfs b/schemes/redoxfs index 3dcaad5..ec00f58 160000 --- a/schemes/redoxfs +++ b/schemes/redoxfs @@ -1 +1 @@ -Subproject commit 3dcaad55fe6e82450c1691da5d515861a7deed0a +Subproject commit ec00f58d73de142332e80d097e32f3d93c2a33bf diff --git a/schemes/tcpd/Cargo.toml b/schemes/tcpd/Cargo.toml index 4fdf599..43db502 100644 --- a/schemes/tcpd/Cargo.toml +++ b/schemes/tcpd/Cargo.toml @@ -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/" } diff --git a/schemes/tcpd/src/main.rs b/schemes/tcpd/src/main.rs index d830a5c..7cfa7ff 100644 --- a/schemes/tcpd/src/main.rs +++ b/schemes/tcpd/src/main.rs @@ -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::().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, + todo_read: VecDeque, + todo_write: VecDeque, +} + +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) -> 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::() << 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) -> Ipv4 { + Ipv4 { + header: Ipv4Header { + ver_hlen: 0x45, + services: 0, + len: n16::new((data.len() + mem::size_of::()) 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, + next_id: usize, + handles: BTreeMap, + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + let _handle = self.handles.get(&file).ok_or(Error::new(EBADF))?; + + Ok(0) + } + + fn close(&mut self, file: usize) -> Result { + + 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> { + 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> { + 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"); }); } diff --git a/schemes/tcpd/src/resource.rs b/schemes/tcpd/src/resource.rs deleted file mode 100644 index 2729682..0000000 --- a/schemes/tcpd/src/resource.rs +++ /dev/null @@ -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 { - 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 { - 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::() << 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 { - 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::()) << 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 { - 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::() << 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::() << 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::() << 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::()) << 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> -} - -impl Resource for TcpResource { - fn dup(&self) -> Result> { - Ok(Box::new(TcpResource { - stream: self.stream.clone() - })) - } - - fn path(&self, buf: &mut [u8]) -> Result { - unsafe { (*self.stream.get()).path(buf) } - } - - fn read(&mut self, buf: &mut [u8]) -> Result { - unsafe { (*self.stream.get()).read(buf) } - } - - fn write(&mut self, buf: &[u8]) -> Result { - unsafe { (*self.stream.get()).write(buf) } - } - - fn sync(&mut self) -> Result { - unsafe { (*self.stream.get()).sync() } - } -} diff --git a/schemes/tcpd/src/scheme.rs b/schemes/tcpd/src/scheme.rs deleted file mode 100644 index b1f3de2..0000000 --- a/schemes/tcpd/src/scheme.rs +++ /dev/null @@ -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 for TcpScheme { - fn open_resource(&self, url: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result> { - 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::().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::().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)) - } -} diff --git a/schemes/udpd/Cargo.toml b/schemes/udpd/Cargo.toml index 6ea76ca..99ccea4 100644 --- a/schemes/udpd/Cargo.toml +++ b/schemes/udpd/Cargo.toml @@ -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/" } diff --git a/schemes/udpd/src/main.rs b/schemes/udpd/src/main.rs index 282a170..c0317cc 100644 --- a/schemes/udpd/src/main.rs +++ b/schemes/udpd/src/main.rs @@ -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::().unwrap_or(0); + (host, port) +} -mod resource; -mod scheme; +struct Handle { + local: (Ipv4Addr, u16), + remote: (Ipv4Addr, u16), + flags: usize, + events: usize, + data: VecDeque>, + todo: VecDeque, +} + +struct Udpd { + scheme_file: File, + udp_file: File, + ports: BTreeMap, + next_id: usize, + handles: BTreeMap, + 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 { + 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 { + 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 { + 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 { + 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::()) 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::()) 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 { + 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 { + 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 { + let _handle = self.handles.get(&file).ok_or(Error::new(EBADF))?; + + Ok(0) + } + + fn close(&mut self, file: usize) -> Result { + 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> { + 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> { + 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"); }); } diff --git a/schemes/udpd/src/resource.rs b/schemes/udpd/src/resource.rs deleted file mode 100644 index 7119fb5..0000000 --- a/schemes/udpd/src/resource.rs +++ /dev/null @@ -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, - pub host_addr: Ipv4Addr, - pub peer_addr: Ipv4Addr, - pub peer_port: u16, - pub host_port: u16, -} - -impl Resource for UdpResource { - fn dup(&self) -> Result> { - 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 { - 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 { - if ! self.data.is_empty() { - let mut bytes: Vec = 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 { - let mut udp = Udp { - header: UdpHeader { - src: n16::new(self.host_port), - dst: n16::new(self.peer_port), - len: n16::new((mem::size_of::() + 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::() + udp.data.len()) as u16); - udp.header.checksum.data = - Checksum::compile(Checksum::sum((&self.host_addr as *const Ipv4Addr) as usize, - mem::size_of::()) + - Checksum::sum((&self.peer_addr as *const Ipv4Addr) as usize, - mem::size_of::()) + - Checksum::sum((&proto as *const n16) as usize, - mem::size_of::()) + - Checksum::sum((&datagram_len as *const n16) as usize, - mem::size_of::()) + - Checksum::sum((&udp.header as *const UdpHeader) as usize, - mem::size_of::()) + - 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 { - syscall::fsync(self.ip) - } -} diff --git a/schemes/udpd/src/scheme.rs b/schemes/udpd/src/scheme.rs deleted file mode 100644 index aad5dee..0000000 --- a/schemes/udpd/src/scheme.rs +++ /dev/null @@ -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 for UdpScheme { - fn open_resource(&self, url: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result> { - 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::().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::().unwrap_or(0); - if peer_port > 0 { - let host_port = path.parse::().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)) - } -} diff --git a/syscall/src/lib.rs b/syscall/src/lib.rs index 7646c00..03a486e 100644 --- a/syscall/src/lib.rs +++ b/syscall/src/lib.rs @@ -48,8 +48,8 @@ pub fn clock_gettime(clock: usize, tp: &mut TimeSpec) -> Result { unsafe { syscall2(SYS_CLOCK_GETTIME, clock, tp as *mut TimeSpec as usize) } } -pub fn dup(fd: usize) -> Result { - unsafe { syscall1(SYS_DUP, fd) } +pub fn dup(fd: usize, buf: &[u8]) -> Result { + unsafe { syscall3(SYS_DUP, fd, buf.as_ptr() as usize, buf.len()) } } pub fn execve(path: &str, args: &[[usize; 2]]) -> Result { diff --git a/syscall/src/scheme.rs b/syscall/src/scheme.rs index a84865f..64255cc 100644 --- a/syscall/src/scheme.rs +++ b/syscall/src/scheme.rs @@ -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 { + fn dup(&self, old_id: usize, buf: &[u8]) -> Result { 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 { + fn dup(&mut self, old_id: usize, buf: &[u8]) -> Result { Err(Error::new(EBADF)) }