Redo networking (#22)
* Rewriting network functions * Add buffer to dup Fix non-blocking handling by triggering once on enabling events to read to EOF * Modifications for UDP API * Implement TCP client side * Add active close * Add DMAR parser * Implement basic TCP listening. Need to improve the state machine * Reduce debugging * Fixes for close procedure * Updates to fix path processing in libstd
This commit is contained in:
parent
268c859fd6
commit
2491e4771e
10
Makefile
10
Makefile
|
@ -42,7 +42,6 @@ clean:
|
||||||
cargo clean --manifest-path programs/userutils/Cargo.toml
|
cargo clean --manifest-path programs/userutils/Cargo.toml
|
||||||
cargo clean --manifest-path programs/smith/Cargo.toml
|
cargo clean --manifest-path programs/smith/Cargo.toml
|
||||||
cargo clean --manifest-path programs/tar/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/ethernetd/Cargo.toml
|
||||||
cargo clean --manifest-path schemes/example/Cargo.toml
|
cargo clean --manifest-path schemes/example/Cargo.toml
|
||||||
cargo clean --manifest-path schemes/ipd/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/userutils/Cargo.toml
|
||||||
cargo update --manifest-path programs/smith/Cargo.toml
|
cargo update --manifest-path programs/smith/Cargo.toml
|
||||||
cargo update --manifest-path programs/tar/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/ethernetd/Cargo.toml
|
||||||
cargo update --manifest-path schemes/example/Cargo.toml
|
cargo update --manifest-path schemes/example/Cargo.toml
|
||||||
cargo update --manifest-path schemes/ipd/Cargo.toml
|
cargo update --manifest-path schemes/ipd/Cargo.toml
|
||||||
|
@ -120,7 +118,12 @@ $(KBUILD)/harddrive.bin: $(KBUILD)/kernel
|
||||||
qemu: $(KBUILD)/harddrive.bin
|
qemu: $(KBUILD)/harddrive.bin
|
||||||
$(QEMU) $(QEMUFLAGS) -kernel $<
|
$(QEMU) $(QEMUFLAGS) -kernel $<
|
||||||
else
|
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)
|
ifeq ($(net),no)
|
||||||
QEMUFLAGS+=-net none
|
QEMUFLAGS+=-net none
|
||||||
else
|
else
|
||||||
|
@ -406,7 +409,6 @@ userutils: \
|
||||||
filesystem/bin/sudo
|
filesystem/bin/sudo
|
||||||
|
|
||||||
schemes: \
|
schemes: \
|
||||||
filesystem/bin/arpd \
|
|
||||||
filesystem/bin/ethernetd \
|
filesystem/bin/ethernetd \
|
||||||
filesystem/bin/example \
|
filesystem/bin/example \
|
||||||
filesystem/bin/ipd \
|
filesystem/bin/ipd \
|
||||||
|
|
170
arch/x86_64/src/acpi/dmar.rs
Normal file
170
arch/x86_64/src/acpi/dmar.rs
Normal file
|
@ -0,0 +1,170 @@
|
||||||
|
use core::mem;
|
||||||
|
|
||||||
|
use super::sdt::Sdt;
|
||||||
|
|
||||||
|
/// The DMA Remapping Table
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Dmar {
|
||||||
|
sdt: &'static Sdt,
|
||||||
|
pub addr_width: u8,
|
||||||
|
pub flags: u8,
|
||||||
|
_rsv: [u8; 10],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Dmar {
|
||||||
|
pub fn new(sdt: &'static Sdt) -> Option<Dmar> {
|
||||||
|
if &sdt.signature == b"DMAR" && sdt.data_len() >= 12 { //Not valid if no local address and flags
|
||||||
|
let addr_width = unsafe { *(sdt.data_address() as *const u8) };
|
||||||
|
let flags = unsafe { *(sdt.data_address() as *const u8).offset(1) };
|
||||||
|
let rsv: [u8; 10] = unsafe { *((sdt.data_address() as *const u8).offset(2) as *const [u8; 10]) };
|
||||||
|
|
||||||
|
Some(Dmar {
|
||||||
|
sdt: sdt,
|
||||||
|
addr_width: addr_width,
|
||||||
|
flags: flags,
|
||||||
|
_rsv: rsv,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter(&self) -> DmarIter {
|
||||||
|
DmarIter {
|
||||||
|
sdt: self.sdt,
|
||||||
|
i: 12 // Skip address width and flags
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
|
||||||
|
/// DMAR DMA Remapping Hardware Unit Definition
|
||||||
|
// TODO: Implement iterator on DmarDrhd scope
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[repr(packed)]
|
||||||
|
pub struct DmarDrhd {
|
||||||
|
kind: u16,
|
||||||
|
length: u16,
|
||||||
|
flags: u8,
|
||||||
|
_rsv: u8,
|
||||||
|
segment: u16,
|
||||||
|
base: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// DMAR Reserved Memory Region Reporting
|
||||||
|
// TODO: Implement iterator on DmarRmrr scope
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[repr(packed)]
|
||||||
|
pub struct DmarRmrr {
|
||||||
|
kind: u16,
|
||||||
|
length: u16,
|
||||||
|
_rsv: u16,
|
||||||
|
segment: u16,
|
||||||
|
base: u64,
|
||||||
|
limit: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// DMAR Root Port ATS Capability Reporting
|
||||||
|
// TODO: Implement iterator on DmarAtsr scope
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[repr(packed)]
|
||||||
|
pub struct DmarAtsr {
|
||||||
|
kind: u16,
|
||||||
|
length: u16,
|
||||||
|
flags: u8,
|
||||||
|
_rsv: u8,
|
||||||
|
segment: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// DMAR Remapping Hardware Static Affinity
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[repr(packed)]
|
||||||
|
pub struct DmarRhsa {
|
||||||
|
kind: u16,
|
||||||
|
length: u16,
|
||||||
|
_rsv: u32,
|
||||||
|
base: u64,
|
||||||
|
domain: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// DMAR ACPI Name-space Device Declaration
|
||||||
|
// TODO: Implement iterator on DmarAndd object name
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[repr(packed)]
|
||||||
|
pub struct DmarAndd {
|
||||||
|
kind: u16,
|
||||||
|
length: u16,
|
||||||
|
_rsv: [u8; 3],
|
||||||
|
acpi_dev: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// DMAR Entries
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum DmarEntry {
|
||||||
|
Drhd(&'static DmarDrhd),
|
||||||
|
InvalidDrhd(usize),
|
||||||
|
Rmrr(&'static DmarRmrr),
|
||||||
|
InvalidRmrr(usize),
|
||||||
|
Atsr(&'static DmarAtsr),
|
||||||
|
InvalidAtsr(usize),
|
||||||
|
Rhsa(&'static DmarRhsa),
|
||||||
|
InvalidRhsa(usize),
|
||||||
|
Andd(&'static DmarAndd),
|
||||||
|
InvalidAndd(usize),
|
||||||
|
Unknown(u16)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DmarIter {
|
||||||
|
sdt: &'static Sdt,
|
||||||
|
i: usize
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Iterator for DmarIter {
|
||||||
|
type Item = DmarEntry;
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
if self.i + 4 <= self.sdt.data_len() {
|
||||||
|
let entry_type = unsafe { *((self.sdt.data_address() as *const u8).offset(self.i as isize) as *const u16) };
|
||||||
|
let entry_len = unsafe { *((self.sdt.data_address() as *const u8).offset(self.i as isize + 2) as *const u16) } as usize;
|
||||||
|
|
||||||
|
if self.i + entry_len <= self.sdt.data_len() {
|
||||||
|
let item = match entry_type {
|
||||||
|
0 => if entry_len >= mem::size_of::<DmarDrhd>() {
|
||||||
|
DmarEntry::Drhd(unsafe { &*((self.sdt.data_address() + self.i) as *const DmarDrhd) })
|
||||||
|
} else {
|
||||||
|
DmarEntry::InvalidDrhd(entry_len)
|
||||||
|
},
|
||||||
|
1 => if entry_len >= mem::size_of::<DmarRmrr>() {
|
||||||
|
DmarEntry::Rmrr(unsafe { &*((self.sdt.data_address() + self.i) as *const DmarRmrr) })
|
||||||
|
} else {
|
||||||
|
DmarEntry::InvalidRmrr(entry_len)
|
||||||
|
},
|
||||||
|
2 => if entry_len >= mem::size_of::<DmarAtsr>() {
|
||||||
|
DmarEntry::Atsr(unsafe { &*((self.sdt.data_address() + self.i) as *const DmarAtsr) })
|
||||||
|
} else {
|
||||||
|
DmarEntry::InvalidAtsr(entry_len)
|
||||||
|
},
|
||||||
|
3 => if entry_len == mem::size_of::<DmarRhsa>() {
|
||||||
|
DmarEntry::Rhsa(unsafe { &*((self.sdt.data_address() + self.i) as *const DmarRhsa) })
|
||||||
|
} else {
|
||||||
|
DmarEntry::InvalidRhsa(entry_len)
|
||||||
|
},
|
||||||
|
4 => if entry_len >= mem::size_of::<DmarAndd>() {
|
||||||
|
DmarEntry::Andd(unsafe { &*((self.sdt.data_address() + self.i) as *const DmarAndd) })
|
||||||
|
} else {
|
||||||
|
DmarEntry::InvalidAndd(entry_len)
|
||||||
|
},
|
||||||
|
_ => DmarEntry::Unknown(entry_type)
|
||||||
|
};
|
||||||
|
|
||||||
|
self.i += entry_len;
|
||||||
|
|
||||||
|
Some(item)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,12 +9,14 @@ use memory::{allocate_frames, Frame};
|
||||||
use paging::{entry, ActivePageTable, Page, PhysicalAddress, VirtualAddress};
|
use paging::{entry, ActivePageTable, Page, PhysicalAddress, VirtualAddress};
|
||||||
use start::{kstart_ap, CPU_COUNT, AP_READY};
|
use start::{kstart_ap, CPU_COUNT, AP_READY};
|
||||||
|
|
||||||
|
use self::dmar::Dmar;
|
||||||
use self::local_apic::LocalApic;
|
use self::local_apic::LocalApic;
|
||||||
use self::madt::{Madt, MadtEntry};
|
use self::madt::{Madt, MadtEntry};
|
||||||
use self::rsdt::Rsdt;
|
use self::rsdt::Rsdt;
|
||||||
use self::sdt::Sdt;
|
use self::sdt::Sdt;
|
||||||
use self::xsdt::Xsdt;
|
use self::xsdt::Xsdt;
|
||||||
|
|
||||||
|
pub mod dmar;
|
||||||
pub mod local_apic;
|
pub mod local_apic;
|
||||||
pub mod madt;
|
pub mod madt;
|
||||||
pub mod rsdt;
|
pub mod rsdt;
|
||||||
|
@ -133,6 +135,12 @@ pub fn init_sdt(sdt: &'static Sdt, active_table: &mut ActivePageTable) {
|
||||||
// Unmap trampoline
|
// Unmap trampoline
|
||||||
active_table.unmap(trampoline_page);
|
active_table.unmap(trampoline_page);
|
||||||
active_table.flush(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 {
|
} else {
|
||||||
println!(": Unknown");
|
println!(": Unknown");
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,13 +38,43 @@ impl<R> EventQueue<R> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Remove a file from the event queue, returning its callback if found
|
||||||
|
pub fn remove(&mut self, fd: RawFd) -> Result<Option<Box<FnMut(usize) -> Result<Option<R>>>>> {
|
||||||
|
if let Some(callback) = self.callbacks.remove(&fd) {
|
||||||
|
syscall::fevent(fd, 0).map_err(|x| Error::from_sys(x))?;
|
||||||
|
|
||||||
|
Ok(Some(callback))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Send an event to a descriptor callback
|
||||||
|
pub fn trigger(&mut self, fd: RawFd, count: usize) -> Result<Option<R>> {
|
||||||
|
if let Some(callback) = self.callbacks.get_mut(&fd) {
|
||||||
|
callback(count)
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Send an event to all descriptor callbacks, useful for cleaning out buffers after init
|
||||||
|
pub fn trigger_all(&mut self, count: usize) -> Result<Vec<R>> {
|
||||||
|
let mut rets = Vec::new();
|
||||||
|
for (_fd, callback) in self.callbacks.iter_mut() {
|
||||||
|
if let Some(ret) = callback(count)? {
|
||||||
|
rets.push(ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(rets)
|
||||||
|
}
|
||||||
|
|
||||||
/// Process the event queue until a callback returns Some(R)
|
/// Process the event queue until a callback returns Some(R)
|
||||||
pub fn run(&mut self) -> Result<R> {
|
pub fn run(&mut self) -> Result<R> {
|
||||||
loop {
|
loop {
|
||||||
let mut event = syscall::Event::default();
|
let mut event = syscall::Event::default();
|
||||||
self.file.read(&mut event)?;
|
if self.file.read(&mut event)? > 0 {
|
||||||
if let Some(callback) = self.callbacks.get_mut(&event.id) {
|
if let Some(ret) = self.trigger(event.id, event.data)? {
|
||||||
if let Some(ret) = callback(event.data)? {
|
|
||||||
return Ok(ret);
|
return Ok(ret);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ use syscall::error::*;
|
||||||
pub trait Resource {
|
pub trait Resource {
|
||||||
/// Duplicate the resource
|
/// Duplicate the resource
|
||||||
/// Returns `EPERM` if the operation is not supported.
|
/// Returns `EPERM` if the operation is not supported.
|
||||||
fn dup(&self) -> Result<Box<Self>> {
|
fn dup(&self, _buf: &[u8]) -> Result<Box<Self>> {
|
||||||
Err(Error::new(EPERM))
|
Err(Error::new(EPERM))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ pub trait ResourceScheme<T: Resource> {
|
||||||
SYS_RMDIR => self.rmdir(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }, packet.uid, packet.gid),
|
SYS_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_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_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_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),
|
SYS_LSEEK => self.seek(packet.b, packet.c, packet.d),
|
||||||
|
@ -54,9 +54,9 @@ pub trait ResourceScheme<T: Resource> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Resource operations */
|
/* Resource operations */
|
||||||
fn dup(&self, old_id: usize) -> Result<usize> {
|
fn dup(&self, old_id: usize, buf: &[u8]) -> Result<usize> {
|
||||||
let old = unsafe { &*(old_id as *const T) };
|
let old = unsafe { &*(old_id as *const T) };
|
||||||
let resource = old.dup()?;
|
let resource = old.dup(buf)?;
|
||||||
let resource_ptr = Box::into_raw(resource);
|
let resource_ptr = Box::into_raw(resource);
|
||||||
Ok(resource_ptr as usize)
|
Ok(resource_ptr as usize)
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,10 +52,14 @@ fn main() {
|
||||||
let mut event = Event::default();
|
let mut event = Event::default();
|
||||||
event_file.read(&mut event).expect("ahcid: failed to read event file");
|
event_file.read(&mut event).expect("ahcid: failed to read event file");
|
||||||
if event.id == socket_fd {
|
if event.id == socket_fd {
|
||||||
|
loop {
|
||||||
let mut packet = Packet::default();
|
let mut packet = Packet::default();
|
||||||
socket.read(&mut packet).expect("ahcid: failed to read disk scheme");
|
if socket.read(&mut packet).expect("ahcid: failed to read disk scheme") == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
scheme.handle(&mut packet);
|
scheme.handle(&mut packet);
|
||||||
socket.write(&mut packet).expect("ahcid: failed to write disk scheme");
|
socket.write(&mut packet).expect("ahcid: failed to write disk scheme");
|
||||||
|
}
|
||||||
} else if event.id == irq_fd {
|
} else if event.id == irq_fd {
|
||||||
let mut irq = [0; 8];
|
let mut irq = [0; 8];
|
||||||
if irq_file.read(&mut irq).expect("ahcid: failed to read irq file") >= irq.len() {
|
if irq_file.read(&mut irq).expect("ahcid: failed to read irq file") >= irq.len() {
|
||||||
|
|
|
@ -47,7 +47,7 @@ impl Scheme for DiskScheme {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dup(&self, id: usize) -> Result<usize> {
|
fn dup(&self, id: usize, _buf: &[u8]) -> Result<usize> {
|
||||||
let mut handles = self.handles.lock();
|
let mut handles = self.handles.lock();
|
||||||
let new_handle = {
|
let new_handle = {
|
||||||
let handle = handles.get(&id).ok_or(Error::new(EBADF))?;
|
let handle = handles.get(&id).ok_or(Error::new(EBADF))?;
|
||||||
|
|
|
@ -109,7 +109,7 @@ impl Scheme for Intel8254x {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dup(&self, id: usize) -> Result<usize> {
|
fn dup(&self, id: usize, _buf: &[u8]) -> Result<usize> {
|
||||||
Ok(id)
|
Ok(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -80,8 +80,11 @@ fn main() {
|
||||||
|
|
||||||
let socket_packet = socket.clone();
|
let socket_packet = socket.clone();
|
||||||
event_queue.add(socket_fd, move |_count: usize| -> Result<Option<usize>> {
|
event_queue.add(socket_fd, move |_count: usize| -> Result<Option<usize>> {
|
||||||
|
loop {
|
||||||
let mut packet = Packet::default();
|
let mut packet = Packet::default();
|
||||||
socket_packet.borrow_mut().read(&mut packet)?;
|
if socket_packet.borrow_mut().read(&mut packet)? == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
let a = packet.a;
|
let a = packet.a;
|
||||||
device.handle(&mut packet);
|
device.handle(&mut packet);
|
||||||
|
@ -91,6 +94,7 @@ fn main() {
|
||||||
} else {
|
} else {
|
||||||
socket_packet.borrow_mut().write(&mut packet)?;
|
socket_packet.borrow_mut().write(&mut packet)?;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let next_read = device.next_read();
|
let next_read = device.next_read();
|
||||||
if next_read > 0 {
|
if next_read > 0 {
|
||||||
|
@ -100,10 +104,8 @@ fn main() {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}).expect("e1000d: failed to catch events on IRQ file");
|
}).expect("e1000d: failed to catch events on IRQ file");
|
||||||
|
|
||||||
loop {
|
for event_count in event_queue.trigger_all(0).expect("e1000d: failed to trigger events") {
|
||||||
let event_count = event_queue.run().expect("e1000d: failed to handle events");
|
socket.borrow_mut().write(&Packet {
|
||||||
|
|
||||||
let event_packet = Packet {
|
|
||||||
id: 0,
|
id: 0,
|
||||||
pid: 0,
|
pid: 0,
|
||||||
uid: 0,
|
uid: 0,
|
||||||
|
@ -112,9 +114,22 @@ fn main() {
|
||||||
b: 0,
|
b: 0,
|
||||||
c: syscall::flag::EVENT_READ,
|
c: syscall::flag::EVENT_READ,
|
||||||
d: event_count
|
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); }
|
unsafe { let _ = syscall::physunmap(address); }
|
||||||
|
|
|
@ -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() {
|
fn main() {
|
||||||
thread::spawn(|| {
|
thread::spawn(|| {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -39,9 +125,11 @@ fn main() {
|
||||||
asm!("cli" :::: "intel", "volatile");
|
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 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");
|
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");
|
}).expect("ps2d: failed to poll irq:12");
|
||||||
|
|
||||||
let mut lshift = false;
|
for (keyboard, data) in event_queue.trigger_all(0).expect("ps2d: failed to trigger events") {
|
||||||
let mut rshift = false;
|
ps2d.handle(keyboard, data);
|
||||||
let mut packets = [0; 4];
|
}
|
||||||
let mut packet_i = 0;
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let (keyboard, data) = event_queue.run().expect("ps2d: failed to handle events");
|
let (keyboard, data) = event_queue.run().expect("ps2d: failed to handle events");
|
||||||
|
ps2d.handle(keyboard, data);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,7 +84,7 @@ impl SchemeMut for Rtl8168 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dup(&mut self, id: usize) -> Result<usize> {
|
fn dup(&mut self, id: usize, _buf: &[u8]) -> Result<usize> {
|
||||||
Ok(id)
|
Ok(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -85,8 +85,11 @@ fn main() {
|
||||||
let socket_fd = socket.borrow().as_raw_fd();
|
let socket_fd = socket.borrow().as_raw_fd();
|
||||||
let socket_packet = socket.clone();
|
let socket_packet = socket.clone();
|
||||||
event_queue.add(socket_fd, move |_count: usize| -> Result<Option<usize>> {
|
event_queue.add(socket_fd, move |_count: usize| -> Result<Option<usize>> {
|
||||||
|
loop {
|
||||||
let mut packet = Packet::default();
|
let mut packet = Packet::default();
|
||||||
socket_packet.borrow_mut().read(&mut packet)?;
|
if socket_packet.borrow_mut().read(&mut packet)? == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
let a = packet.a;
|
let a = packet.a;
|
||||||
device.borrow_mut().handle(&mut packet);
|
device.borrow_mut().handle(&mut packet);
|
||||||
|
@ -96,6 +99,7 @@ fn main() {
|
||||||
} else {
|
} else {
|
||||||
socket_packet.borrow_mut().write(&mut packet)?;
|
socket_packet.borrow_mut().write(&mut packet)?;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let next_read = device.borrow().next_read();
|
let next_read = device.borrow().next_read();
|
||||||
if next_read > 0 {
|
if next_read > 0 {
|
||||||
|
@ -105,10 +109,8 @@ fn main() {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}).expect("rtl8168d: failed to catch events on IRQ file");
|
}).expect("rtl8168d: failed to catch events on IRQ file");
|
||||||
|
|
||||||
loop {
|
for event_count in event_queue.trigger_all(0).expect("rtl8168d: failed to trigger events") {
|
||||||
let event_count = event_queue.run().expect("rtl8168d: failed to handle events");
|
socket.borrow_mut().write(&Packet {
|
||||||
|
|
||||||
let event_packet = Packet {
|
|
||||||
id: 0,
|
id: 0,
|
||||||
pid: 0,
|
pid: 0,
|
||||||
uid: 0,
|
uid: 0,
|
||||||
|
@ -117,9 +119,22 @@ fn main() {
|
||||||
b: 0,
|
b: 0,
|
||||||
c: syscall::flag::EVENT_READ,
|
c: syscall::flag::EVENT_READ,
|
||||||
d: event_count
|
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); }
|
unsafe { let _ = syscall::physunmap(address); }
|
||||||
|
|
|
@ -63,7 +63,6 @@ fn main() {
|
||||||
loop {
|
loop {
|
||||||
let mut packet = Packet::default();
|
let mut packet = Packet::default();
|
||||||
socket.read(&mut packet).expect("vesad: failed to read display scheme");
|
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 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) {
|
if packet.a == syscall::number::SYS_READ && packet.d > 0 && scheme.will_block(packet.b) {
|
||||||
|
|
|
@ -60,7 +60,7 @@ impl SchemeMut for DisplayScheme {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dup(&mut self, id: usize) -> Result<usize> {
|
fn dup(&mut self, id: usize, _buf: &[u8]) -> Result<usize> {
|
||||||
Ok(id)
|
Ok(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
randd
|
randd
|
||||||
initfs:bin/pcid /etc/pcid.toml
|
initfs:bin/pcid /etc/pcid.toml
|
||||||
ethernetd
|
ethernetd
|
||||||
arpd
|
|
||||||
ipd
|
ipd
|
||||||
tcpd
|
tcpd
|
||||||
udpd
|
udpd
|
||||||
|
|
|
@ -33,7 +33,7 @@ impl Scheme for DebugScheme {
|
||||||
Ok(0)
|
Ok(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dup(&self, _file: usize) -> Result<usize> {
|
fn dup(&self, _file: usize, _buf: &[u8]) -> Result<usize> {
|
||||||
Ok(0)
|
Ok(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -88,7 +88,7 @@ impl Scheme for EnvScheme {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dup(&self, id: usize) -> Result<usize> {
|
fn dup(&self, id: usize, _buf: &[u8]) -> Result<usize> {
|
||||||
let new_handle = {
|
let new_handle = {
|
||||||
let handles = self.handles.read();
|
let handles = self.handles.read();
|
||||||
let handle = handles.get(&id).ok_or(Error::new(EBADF))?;
|
let handle = handles.get(&id).ok_or(Error::new(EBADF))?;
|
||||||
|
|
|
@ -39,7 +39,7 @@ impl Scheme for EventScheme {
|
||||||
Ok(id)
|
Ok(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dup(&self, id: usize) -> Result<usize> {
|
fn dup(&self, id: usize, _buf: &[u8]) -> Result<usize> {
|
||||||
let handle = {
|
let handle = {
|
||||||
let handles = self.handles.read();
|
let handles = self.handles.read();
|
||||||
let handle_weak = handles.get(&id).ok_or(Error::new(EBADF))?;
|
let handle_weak = handles.get(&id).ok_or(Error::new(EBADF))?;
|
||||||
|
|
|
@ -57,7 +57,7 @@ impl Scheme for InitFsScheme {
|
||||||
Err(Error::new(ENOENT))
|
Err(Error::new(ENOENT))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dup(&self, id: usize) -> Result<usize> {
|
fn dup(&self, id: usize, _buf: &[u8]) -> Result<usize> {
|
||||||
let (path, data, mode, seek) = {
|
let (path, data, mode, seek) = {
|
||||||
let handles = self.handles.read();
|
let handles = self.handles.read();
|
||||||
let handle = handles.get(&id).ok_or(Error::new(EBADF))?;
|
let handle = handles.get(&id).ok_or(Error::new(EBADF))?;
|
||||||
|
|
|
@ -40,7 +40,7 @@ impl Scheme for IrqScheme {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dup(&self, file: usize) -> Result<usize> {
|
fn dup(&self, file: usize, _buf: &[u8]) -> Result<usize> {
|
||||||
Ok(file)
|
Ok(file)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ pub fn pipe(flags: usize) -> (usize, usize) {
|
||||||
pub struct PipeScheme;
|
pub struct PipeScheme;
|
||||||
|
|
||||||
impl Scheme for PipeScheme {
|
impl Scheme for PipeScheme {
|
||||||
fn dup(&self, id: usize) -> Result<usize> {
|
fn dup(&self, id: usize, _buf: &[u8]) -> Result<usize> {
|
||||||
let mut pipes = pipes_mut();
|
let mut pipes = pipes_mut();
|
||||||
|
|
||||||
let read_option = pipes.0.get(&id).map(|pipe| pipe.clone());
|
let read_option = pipes.0.get(&id).map(|pipe| pipe.clone());
|
||||||
|
|
|
@ -56,7 +56,7 @@ impl Scheme for RootScheme {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dup(&self, file: usize) -> Result<usize> {
|
fn dup(&self, file: usize, _buf: &[u8]) -> Result<usize> {
|
||||||
let mut handles = self.handles.write();
|
let mut handles = self.handles.write();
|
||||||
let inner = {
|
let inner = {
|
||||||
let inner = handles.get(&file).ok_or(Error::new(EBADF))?;
|
let inner = handles.get(&file).ok_or(Error::new(EBADF))?;
|
||||||
|
@ -89,12 +89,24 @@ impl Scheme for RootScheme {
|
||||||
inner.write(buf)
|
inner.write(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fevent(&self, file: usize, _flags: usize) -> Result<usize> {
|
fn fevent(&self, file: usize, flags: usize) -> Result<usize> {
|
||||||
Ok(file)
|
let inner = {
|
||||||
|
let handles = self.handles.read();
|
||||||
|
let inner = handles.get(&file).ok_or(Error::new(EBADF))?;
|
||||||
|
inner.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
inner.fevent(flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fsync(&self, _file: usize) -> Result<usize> {
|
fn fsync(&self, file: usize) -> Result<usize> {
|
||||||
Ok(0)
|
let inner = {
|
||||||
|
let handles = self.handles.read();
|
||||||
|
let inner = handles.get(&file).ok_or(Error::new(EBADF))?;
|
||||||
|
inner.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
inner.fsync()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn close(&self, file: usize) -> Result<usize> {
|
fn close(&self, file: usize) -> Result<usize> {
|
||||||
|
|
|
@ -92,7 +92,7 @@ impl Scheme for SysScheme {
|
||||||
Err(Error::new(ENOENT))
|
Err(Error::new(ENOENT))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dup(&self, id: usize) -> Result<usize> {
|
fn dup(&self, id: usize, _buf: &[u8]) -> Result<usize> {
|
||||||
let (path, data, mode, seek) = {
|
let (path, data, mode, seek) = {
|
||||||
let handles = self.handles.read();
|
let handles = self.handles.read();
|
||||||
let handle = handles.get(&id).ok_or(Error::new(EBADF))?;
|
let handle = handles.get(&id).ok_or(Error::new(EBADF))?;
|
||||||
|
|
|
@ -61,10 +61,7 @@ impl UserInner {
|
||||||
};
|
};
|
||||||
|
|
||||||
let len = self.todo.send(packet);
|
let len = self.todo.send(packet);
|
||||||
//TODO: Use O_NONBLOCK and send one notification
|
context::event::trigger(ROOT_SCHEME_ID.load(Ordering::SeqCst), self.handle_id, EVENT_READ, mem::size_of::<Packet>() * len);
|
||||||
for _i in 0 .. len {
|
|
||||||
context::event::trigger(ROOT_SCHEME_ID.load(Ordering::SeqCst), self.handle_id, EVENT_READ, mem::size_of::<Packet>());
|
|
||||||
}
|
|
||||||
|
|
||||||
Error::demux(self.done.receive(&id))
|
Error::demux(self.done.receive(&id))
|
||||||
}
|
}
|
||||||
|
@ -182,6 +179,14 @@ impl UserInner {
|
||||||
|
|
||||||
Ok(i * packet_size)
|
Ok(i * packet_size)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn fevent(&self, _flags: usize) -> Result<usize> {
|
||||||
|
Ok(self.handle_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fsync(&self) -> Result<usize> {
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// UserInner has to be wrapped
|
/// UserInner has to be wrapped
|
||||||
|
@ -230,9 +235,12 @@ impl Scheme for UserScheme {
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dup(&self, file: usize) -> Result<usize> {
|
fn dup(&self, file: usize, buf: &[u8]) -> Result<usize> {
|
||||||
let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?;
|
let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?;
|
||||||
inner.call(SYS_DUP, file, 0, 0)
|
let address = inner.capture(buf)?;
|
||||||
|
let result = inner.call(SYS_DUP, file, address, buf.len());
|
||||||
|
let _ = inner.release(address);
|
||||||
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read(&self, file: usize, buf: &mut [u8]) -> Result<usize> {
|
fn read(&self, file: usize, buf: &mut [u8]) -> Result<usize> {
|
||||||
|
|
|
@ -83,10 +83,10 @@ pub fn open(path: &[u8], flags: usize) -> Result<usize> {
|
||||||
let reference_opt = parts.next();
|
let reference_opt = parts.next();
|
||||||
|
|
||||||
let (scheme_id, file_id) = {
|
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 (scheme_id, scheme) = {
|
||||||
let schemes = scheme::schemes();
|
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())
|
(scheme_id, scheme.clone())
|
||||||
};
|
};
|
||||||
let file_id = scheme.open(reference_opt.unwrap_or(b""), flags, uid, gid)?;
|
let file_id = scheme.open(reference_opt.unwrap_or(b""), flags, uid, gid)?;
|
||||||
|
@ -146,10 +146,10 @@ pub fn mkdir(path: &[u8], mode: u16) -> Result<usize> {
|
||||||
let namespace_opt = parts.next();
|
let namespace_opt = parts.next();
|
||||||
let reference_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 scheme = {
|
||||||
let schemes = scheme::schemes();
|
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.clone()
|
||||||
};
|
};
|
||||||
scheme.mkdir(reference_opt.unwrap_or(b""), mode, uid, gid)
|
scheme.mkdir(reference_opt.unwrap_or(b""), mode, uid, gid)
|
||||||
|
@ -168,10 +168,10 @@ pub fn rmdir(path: &[u8]) -> Result<usize> {
|
||||||
let namespace_opt = parts.next();
|
let namespace_opt = parts.next();
|
||||||
let reference_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 scheme = {
|
||||||
let schemes = scheme::schemes();
|
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.clone()
|
||||||
};
|
};
|
||||||
scheme.rmdir(reference_opt.unwrap_or(b""), uid, gid)
|
scheme.rmdir(reference_opt.unwrap_or(b""), uid, gid)
|
||||||
|
@ -190,10 +190,10 @@ pub fn unlink(path: &[u8]) -> Result<usize> {
|
||||||
let namespace_opt = parts.next();
|
let namespace_opt = parts.next();
|
||||||
let reference_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 scheme = {
|
||||||
let schemes = scheme::schemes();
|
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.clone()
|
||||||
};
|
};
|
||||||
scheme.unlink(reference_opt.unwrap_or(b""), uid, gid)
|
scheme.unlink(reference_opt.unwrap_or(b""), uid, gid)
|
||||||
|
@ -222,7 +222,7 @@ pub fn close(fd: usize) -> Result<usize> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Duplicate file descriptor
|
/// Duplicate file descriptor
|
||||||
pub fn dup(fd: usize) -> Result<usize> {
|
pub fn dup(fd: usize, buf: &[u8]) -> Result<usize> {
|
||||||
let file = {
|
let file = {
|
||||||
let contexts = context::contexts();
|
let contexts = context::contexts();
|
||||||
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
|
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
|
||||||
|
@ -237,7 +237,7 @@ pub fn dup(fd: usize) -> Result<usize> {
|
||||||
let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?;
|
let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?;
|
||||||
scheme.clone()
|
scheme.clone()
|
||||||
};
|
};
|
||||||
scheme.dup(file.number)?
|
scheme.dup(file.number, buf)?
|
||||||
};
|
};
|
||||||
|
|
||||||
let contexts = context::contexts();
|
let contexts = context::contexts();
|
||||||
|
|
|
@ -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)?),
|
SYS_ARG_MSLICE => file_op_mut_slice(a, b, validate_slice_mut(c as *mut u8, d)?),
|
||||||
_ => match a {
|
_ => match a {
|
||||||
SYS_CLOSE => close(b),
|
SYS_CLOSE => close(b),
|
||||||
SYS_DUP => dup(b),
|
SYS_DUP => dup(b, validate_slice(c as *const u8, d)?),
|
||||||
SYS_FEVENT => fevent(b, c),
|
SYS_FEVENT => fevent(b, c),
|
||||||
_ => file_op(a, b, c, d)
|
_ => file_op(a, b, c, d)
|
||||||
}
|
}
|
||||||
|
|
|
@ -227,7 +227,7 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<usize> {
|
||||||
let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?;
|
let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?;
|
||||||
scheme.clone()
|
scheme.clone()
|
||||||
};
|
};
|
||||||
let result = scheme.dup(file.number);
|
let result = scheme.dup(file.number, &[]);
|
||||||
result
|
result
|
||||||
};
|
};
|
||||||
match result {
|
match result {
|
||||||
|
|
2
libstd
2
libstd
|
@ -1 +1 @@
|
||||||
Subproject commit 4f642eed87af22913af7bef9c71910ee1765445e
|
Subproject commit a390903a03d7cebe448af803e635a46fa1609262
|
|
@ -1 +1 @@
|
||||||
Subproject commit 9faaf3a9690186a12da980fb877c8f05faea62aa
|
Subproject commit 1afcf7ab26ca3f697082674e6a72c94dd211c74b
|
|
@ -1 +1 @@
|
||||||
Subproject commit 4eae543a60a5d6b0298db09bc48b2e6fab60b021
|
Subproject commit 6926b235c47488f1bb2f5574a0445c7698e3ab99
|
|
@ -1 +1 @@
|
||||||
Subproject commit 517ca6d125e90d6b30e45a759f54b1d1b3b346d4
|
Subproject commit 78cd23bf67adad79fb3e45ae4647055b01df026f
|
|
@ -1,7 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "arpd"
|
|
||||||
version = "0.1.0"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
netutils = { path = "../../programs/netutils/" }
|
|
||||||
syscall = { path = "../../syscall/" }
|
|
|
@ -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");
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -68,8 +68,11 @@ fn main() {
|
||||||
}).expect("ethernetd: failed to listen for network events");
|
}).expect("ethernetd: failed to listen for network events");
|
||||||
|
|
||||||
event_queue.add(socket_fd, move |_count: usize| -> Result<Option<()>> {
|
event_queue.add(socket_fd, move |_count: usize| -> Result<Option<()>> {
|
||||||
|
loop {
|
||||||
let mut packet = Packet::default();
|
let mut packet = Packet::default();
|
||||||
socket.borrow_mut().read(&mut packet)?;
|
if socket.borrow_mut().read(&mut packet)? == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
let a = packet.a;
|
let a = packet.a;
|
||||||
scheme.borrow_mut().handle(&mut packet);
|
scheme.borrow_mut().handle(&mut packet);
|
||||||
|
@ -79,10 +82,13 @@ fn main() {
|
||||||
} else {
|
} else {
|
||||||
socket.borrow_mut().write(&mut packet)?;
|
socket.borrow_mut().write(&mut packet)?;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}).expect("ethernetd: failed to listen for scheme events");
|
}).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");
|
event_queue.run().expect("ethernetd: failed to run event loop");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,21 @@
|
||||||
use std::collections::{BTreeMap, VecDeque};
|
use std::collections::{BTreeMap, VecDeque};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{self, Read};
|
use std::io::{self, Read, Write};
|
||||||
use std::os::unix::io::AsRawFd;
|
use std::os::unix::io::AsRawFd;
|
||||||
use std::{cmp, str, u16};
|
use std::{cmp, str, u16};
|
||||||
|
|
||||||
use netutils::{getcfg, n16, MacAddr, EthernetII, EthernetIIHeader};
|
use netutils::{getcfg, MacAddr, EthernetII};
|
||||||
use syscall;
|
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;
|
use syscall::scheme::SchemeMut;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Handle {
|
pub struct Handle {
|
||||||
|
/// The flags this handle was opened with
|
||||||
|
flags: usize,
|
||||||
/// The Host's MAC address
|
/// The Host's MAC address
|
||||||
pub host_addr: MacAddr,
|
pub host_addr: MacAddr,
|
||||||
/// The Peer's MAC address
|
|
||||||
pub peer_addr: Option<MacAddr>,
|
|
||||||
/// The ethernet type
|
/// The ethernet type
|
||||||
pub ethertype: u16,
|
pub ethertype: u16,
|
||||||
/// The data
|
/// The data
|
||||||
|
@ -39,65 +40,51 @@ impl EthernetScheme {
|
||||||
//TODO: Minimize allocation
|
//TODO: Minimize allocation
|
||||||
//TODO: Reduce iteration cost (use BTreeMap of ethertype to handle?)
|
//TODO: Reduce iteration cost (use BTreeMap of ethertype to handle?)
|
||||||
pub fn input(&mut self) -> io::Result<usize> {
|
pub fn input(&mut self) -> io::Result<usize> {
|
||||||
|
let mut total = 0;
|
||||||
|
loop {
|
||||||
let mut bytes = [0; 65536];
|
let mut bytes = [0; 65536];
|
||||||
let count = self.network.read(&mut bytes)?;
|
let count = self.network.read(&mut bytes)?;
|
||||||
|
if count == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
if let Some(frame) = EthernetII::from_bytes(&bytes[.. count]) {
|
if let Some(frame) = EthernetII::from_bytes(&bytes[.. count]) {
|
||||||
for (_id, handle) in self.handles.iter_mut() {
|
for (_id, handle) in self.handles.iter_mut() {
|
||||||
if frame.header.ethertype.get() == handle.ethertype {
|
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());
|
handle.frames.push_back(frame.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(count)
|
total += count;
|
||||||
} else {
|
|
||||||
Ok(0)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Ok(total)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SchemeMut for EthernetScheme {
|
impl SchemeMut for EthernetScheme {
|
||||||
fn open(&mut self, url: &[u8], _flags: usize, uid: u32, _gid: u32) -> Result<usize> {
|
fn open(&mut self, url: &[u8], flags: usize, uid: u32, _gid: u32) -> Result<usize> {
|
||||||
if uid == 0 {
|
if uid == 0 {
|
||||||
let mac_addr = MacAddr::from_str(&getcfg("mac").map_err(|err| err.into_sys())?);
|
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 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() {
|
let ethertype = u16::from_str_radix(path, 16).unwrap_or(0);
|
||||||
Some(MacAddr::from_str(host_string))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let next_id = self.next_id;
|
let next_id = self.next_id;
|
||||||
self.next_id += 1;
|
self.next_id += 1;
|
||||||
|
|
||||||
self.handles.insert(next_id, Handle {
|
self.handles.insert(next_id, Handle {
|
||||||
|
flags: flags,
|
||||||
host_addr: mac_addr,
|
host_addr: mac_addr,
|
||||||
peer_addr: peer_addr,
|
|
||||||
ethertype: ethertype,
|
ethertype: ethertype,
|
||||||
frames: VecDeque::new()
|
frames: VecDeque::new()
|
||||||
});
|
});
|
||||||
|
|
||||||
return Ok(next_id);
|
Ok(next_id)
|
||||||
} else {
|
|
||||||
println!("Ethernet: No ethertype provided");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
println!("Ethernet: No host provided");
|
|
||||||
}
|
|
||||||
|
|
||||||
Err(Error::new(ENOENT))
|
|
||||||
} else {
|
} else {
|
||||||
Err(Error::new(EACCES))
|
Err(Error::new(EACCES))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dup(&mut self, id: usize) -> Result<usize> {
|
fn dup(&mut self, id: usize, _buf: &[u8]) -> Result<usize> {
|
||||||
let next_id = self.next_id;
|
let next_id = self.next_id;
|
||||||
self.next_id += 1;
|
self.next_id += 1;
|
||||||
|
|
||||||
|
@ -115,11 +102,14 @@ impl SchemeMut for EthernetScheme {
|
||||||
let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?;
|
let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?;
|
||||||
|
|
||||||
if let Some(frame) = handle.frames.pop_front() {
|
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;
|
*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 {
|
} else {
|
||||||
Err(Error::new(EWOULDBLOCK))
|
Err(Error::new(EWOULDBLOCK))
|
||||||
}
|
}
|
||||||
|
@ -128,17 +118,12 @@ impl SchemeMut for EthernetScheme {
|
||||||
fn write(&mut self, id: usize, buf: &[u8]) -> Result<usize> {
|
fn write(&mut self, id: usize, buf: &[u8]) -> Result<usize> {
|
||||||
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
|
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
|
||||||
|
|
||||||
match syscall::write(self.network.as_raw_fd(), &EthernetII {
|
if let Some(mut frame) = EthernetII::from_bytes(buf) {
|
||||||
header: EthernetIIHeader {
|
frame.header.src = handle.host_addr;
|
||||||
src: handle.host_addr,
|
frame.header.ethertype.set(handle.ethertype);
|
||||||
dst: handle.peer_addr.unwrap_or(MacAddr::BROADCAST),
|
self.network.write(&frame.to_bytes()).map_err(|err| err.into_sys())
|
||||||
ethertype: n16::new(handle.ethertype),
|
} else {
|
||||||
},
|
Err(Error::new(EINVAL))
|
||||||
data: Vec::from(buf),
|
|
||||||
}
|
|
||||||
.to_bytes()) {
|
|
||||||
Ok(_) => Ok(buf.len()),
|
|
||||||
Err(err) => Err(err),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,14 +136,16 @@ impl SchemeMut for EthernetScheme {
|
||||||
fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result<usize> {
|
fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result<usize> {
|
||||||
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
|
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();
|
let path = path_string.as_bytes();
|
||||||
|
|
||||||
for (b, p) in buf.iter_mut().zip(path.iter()) {
|
let mut i = 0;
|
||||||
*b = *p;
|
while i < buf.len() && i < path.len() {
|
||||||
|
buf[i] = path[i];
|
||||||
|
i += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(cmp::min(buf.len(), path.len()))
|
Ok(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fsync(&mut self, id: usize) -> Result<usize> {
|
fn fsync(&mut self, id: usize) -> Result<usize> {
|
||||||
|
@ -169,7 +156,9 @@ impl SchemeMut for EthernetScheme {
|
||||||
|
|
||||||
fn close(&mut self, id: usize) -> Result<usize> {
|
fn close(&mut self, id: usize) -> Result<usize> {
|
||||||
let handle = self.handles.remove(&id).ok_or(Error::new(EBADF))?;
|
let handle = self.handles.remove(&id).ok_or(Error::new(EBADF))?;
|
||||||
|
|
||||||
drop(handle);
|
drop(handle);
|
||||||
|
|
||||||
Ok(0)
|
Ok(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ impl Scheme for ExampleScheme {
|
||||||
Ok(0)
|
Ok(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dup(&self, file: usize) -> Result<usize> {
|
fn dup(&self, file: usize, _buf: &[u8]) -> Result<usize> {
|
||||||
Ok(file)
|
Ok(file)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,6 @@ name = "ipd"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
event = { path = "../../crates/event/" }
|
||||||
netutils = { path = "../../programs/netutils/" }
|
netutils = { path = "../../programs/netutils/" }
|
||||||
resource_scheme = { path = "../../crates/resource_scheme/" }
|
|
||||||
syscall = { path = "../../syscall/" }
|
syscall = { path = "../../syscall/" }
|
||||||
|
|
|
@ -1,120 +1,371 @@
|
||||||
#![feature(rand)]
|
extern crate event;
|
||||||
|
|
||||||
//! 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 netutils;
|
extern crate netutils;
|
||||||
extern crate resource_scheme;
|
|
||||||
extern crate syscall;
|
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::fs::File;
|
||||||
use std::io::{Read, Write};
|
use std::io::{self, Read, Write};
|
||||||
use std::thread;
|
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;
|
struct Interface {
|
||||||
use syscall::Packet;
|
mac: MacAddr,
|
||||||
|
ip: Ipv4Addr,
|
||||||
|
router: Ipv4Addr,
|
||||||
|
subnet: Ipv4Addr,
|
||||||
|
arp_file: File,
|
||||||
|
ip_file: File,
|
||||||
|
arp: BTreeMap<Ipv4Addr, MacAddr>,
|
||||||
|
rarp: BTreeMap<MacAddr, Ipv4Addr>,
|
||||||
|
}
|
||||||
|
|
||||||
use scheme::IpScheme;
|
impl Interface {
|
||||||
|
fn new(arp_fd: usize, ip_fd: usize) -> Self {
|
||||||
|
Interface {
|
||||||
|
mac: MacAddr::from_str(&getcfg("mac").unwrap()),
|
||||||
|
ip: Ipv4Addr::from_str(&getcfg("ip").unwrap()),
|
||||||
|
router: Ipv4Addr::from_str(&getcfg("ip_router").unwrap()),
|
||||||
|
subnet: Ipv4Addr::from_str(&getcfg("ip_subnet").unwrap()),
|
||||||
|
arp_file: unsafe { File::from_raw_fd(arp_fd) },
|
||||||
|
ip_file: unsafe { File::from_raw_fd(ip_fd) },
|
||||||
|
arp: BTreeMap::new(),
|
||||||
|
rarp: BTreeMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mod resource;
|
struct Handle {
|
||||||
mod scheme;
|
proto: u8,
|
||||||
|
flags: usize,
|
||||||
|
events: usize,
|
||||||
|
data: VecDeque<Vec<u8>>,
|
||||||
|
todo: VecDeque<Packet>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Ipd {
|
||||||
|
scheme_file: File,
|
||||||
|
interfaces: Vec<Interface>,
|
||||||
|
next_id: usize,
|
||||||
|
handles: BTreeMap<usize, Handle>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ipd {
|
||||||
|
fn new(scheme_file: File) -> Self {
|
||||||
|
Ipd {
|
||||||
|
scheme_file: scheme_file,
|
||||||
|
interfaces: Vec::new(),
|
||||||
|
next_id: 1,
|
||||||
|
handles: BTreeMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn scheme_event(&mut self) -> io::Result<()> {
|
||||||
|
loop {
|
||||||
|
let mut packet = Packet::default();
|
||||||
|
if self.scheme_file.read(&mut packet)? == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let a = packet.a;
|
||||||
|
self.handle(&mut packet);
|
||||||
|
if packet.a == (-EWOULDBLOCK) as usize {
|
||||||
|
packet.a = a;
|
||||||
|
if let Some(mut handle) = self.handles.get_mut(&packet.b) {
|
||||||
|
handle.todo.push_back(packet);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.scheme_file.write(&packet)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn arp_event(&mut self, if_id: usize) -> io::Result<()> {
|
||||||
|
if let Some(mut interface) = self.interfaces.get_mut(if_id) {
|
||||||
|
loop {
|
||||||
|
let mut bytes = [0; 65536];
|
||||||
|
let count = interface.arp_file.read(&mut bytes)?;
|
||||||
|
if count == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if let Some(frame) = EthernetII::from_bytes(&bytes[.. count]) {
|
||||||
|
if let Some(packet) = Arp::from_bytes(&frame.data) {
|
||||||
|
if packet.header.oper.get() == 1 {
|
||||||
|
if packet.header.dst_ip == interface.ip {
|
||||||
|
let mut response = Arp {
|
||||||
|
header: packet.header,
|
||||||
|
data: packet.data.clone(),
|
||||||
|
};
|
||||||
|
response.header.oper.set(2);
|
||||||
|
response.header.dst_mac = packet.header.src_mac;
|
||||||
|
response.header.dst_ip = packet.header.src_ip;
|
||||||
|
response.header.src_mac = interface.mac;
|
||||||
|
response.header.src_ip = interface.ip;
|
||||||
|
|
||||||
|
let mut response_frame = EthernetII {
|
||||||
|
header: frame.header,
|
||||||
|
data: response.to_bytes()
|
||||||
|
};
|
||||||
|
|
||||||
|
response_frame.header.dst = response_frame.header.src;
|
||||||
|
response_frame.header.src = interface.mac;
|
||||||
|
|
||||||
|
interface.arp_file.write(&response_frame.to_bytes())?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ip_event(&mut self, if_id: usize) -> io::Result<()> {
|
||||||
|
if let Some(mut interface) = self.interfaces.get_mut(if_id) {
|
||||||
|
loop {
|
||||||
|
let mut bytes = [0; 65536];
|
||||||
|
let count = interface.ip_file.read(&mut bytes)?;
|
||||||
|
if count == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if let Some(frame) = EthernetII::from_bytes(&bytes[.. count]) {
|
||||||
|
if let Some(ip) = Ipv4::from_bytes(&frame.data) {
|
||||||
|
if ip.header.dst == interface.ip || ip.header.dst == Ipv4Addr::BROADCAST {
|
||||||
|
//TODO: Handle ping here
|
||||||
|
for (id, handle) in self.handles.iter_mut() {
|
||||||
|
if ip.header.proto == handle.proto {
|
||||||
|
handle.data.push_back(frame.data.clone());
|
||||||
|
|
||||||
|
while ! handle.todo.is_empty() && ! handle.data.is_empty() {
|
||||||
|
let mut packet = handle.todo.pop_front().unwrap();
|
||||||
|
let buf = unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) };
|
||||||
|
let data = handle.data.pop_front().unwrap();
|
||||||
|
|
||||||
|
let mut i = 0;
|
||||||
|
while i < buf.len() && i < data.len() {
|
||||||
|
buf[i] = data[i];
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
packet.a = i;
|
||||||
|
|
||||||
|
self.scheme_file.write(&packet)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if handle.events & EVENT_READ == EVENT_READ {
|
||||||
|
if let Some(data) = handle.data.get(0) {
|
||||||
|
self.scheme_file.write(&Packet {
|
||||||
|
id: 0,
|
||||||
|
pid: 0,
|
||||||
|
uid: 0,
|
||||||
|
gid: 0,
|
||||||
|
a: syscall::number::SYS_FEVENT,
|
||||||
|
b: *id,
|
||||||
|
c: EVENT_READ,
|
||||||
|
d: data.len()
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SchemeMut for Ipd {
|
||||||
|
fn open(&mut self, url: &[u8], flags: usize, uid: u32, _gid: u32) -> Result<usize> {
|
||||||
|
if uid == 0 {
|
||||||
|
let path = str::from_utf8(url).or(Err(Error::new(EINVAL)))?;
|
||||||
|
|
||||||
|
let proto = u8::from_str_radix(path, 16).or(Err(Error::new(ENOENT)))?;
|
||||||
|
|
||||||
|
let id = self.next_id;
|
||||||
|
self.next_id += 1;
|
||||||
|
|
||||||
|
self.handles.insert(id, Handle {
|
||||||
|
proto: proto,
|
||||||
|
flags: flags,
|
||||||
|
events: 0,
|
||||||
|
data: VecDeque::new(),
|
||||||
|
todo: VecDeque::new(),
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(id)
|
||||||
|
} else {
|
||||||
|
Err(Error::new(EACCES))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dup(&mut self, file: usize, _buf: &[u8]) -> Result<usize> {
|
||||||
|
let handle = {
|
||||||
|
let handle = self.handles.get(&file).ok_or(Error::new(EBADF))?;
|
||||||
|
Handle {
|
||||||
|
proto: handle.proto,
|
||||||
|
flags: handle.flags,
|
||||||
|
events: 0,
|
||||||
|
data: handle.data.clone(),
|
||||||
|
todo: VecDeque::new(),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let id = self.next_id;
|
||||||
|
self.next_id += 1;
|
||||||
|
|
||||||
|
self.handles.insert(id, handle);
|
||||||
|
|
||||||
|
Ok(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read(&mut self, file: usize, buf: &mut [u8]) -> Result<usize> {
|
||||||
|
let mut handle = self.handles.get_mut(&file).ok_or(Error::new(EBADF))?;
|
||||||
|
|
||||||
|
if let Some(data) = handle.data.pop_front() {
|
||||||
|
let mut i = 0;
|
||||||
|
while i < buf.len() && i < data.len() {
|
||||||
|
buf[i] = data[i];
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(i)
|
||||||
|
} else if handle.flags & O_NONBLOCK == O_NONBLOCK {
|
||||||
|
Ok(0)
|
||||||
|
} else {
|
||||||
|
Err(Error::new(EWOULDBLOCK))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(&mut self, file: usize, buf: &[u8]) -> Result<usize> {
|
||||||
|
let handle = self.handles.get(&file).ok_or(Error::new(EBADF))?;
|
||||||
|
|
||||||
|
if let Some(mut ip) = Ipv4::from_bytes(buf) {
|
||||||
|
for mut interface in self.interfaces.iter_mut() {
|
||||||
|
if ip.header.src == interface.ip || ip.header.src == Ipv4Addr::NULL {
|
||||||
|
ip.header.src = interface.ip;
|
||||||
|
ip.header.proto = handle.proto;
|
||||||
|
|
||||||
|
if let Some(mut tcp) = Tcp::from_bytes(&ip.data) {
|
||||||
|
tcp.checksum(&ip.header.src, &ip.header.dst);
|
||||||
|
ip.data = tcp.to_bytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
ip.checksum();
|
||||||
|
|
||||||
|
let frame = EthernetII {
|
||||||
|
header: EthernetIIHeader {
|
||||||
|
//TODO: Get real dst
|
||||||
|
dst: MacAddr::BROADCAST,
|
||||||
|
src: interface.mac,
|
||||||
|
ethertype: n16::new(0x800),
|
||||||
|
},
|
||||||
|
data: ip.to_bytes()
|
||||||
|
};
|
||||||
|
|
||||||
|
interface.ip_file.write(&frame.to_bytes()).map_err(|err| err.into_sys())?;
|
||||||
|
|
||||||
|
return Ok(buf.len());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(Error::new(EADDRNOTAVAIL))
|
||||||
|
} else {
|
||||||
|
Err(Error::new(EINVAL))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fevent(&mut self, file: usize, flags: usize) -> Result<usize> {
|
||||||
|
let mut handle = self.handles.get_mut(&file).ok_or(Error::new(EBADF))?;
|
||||||
|
|
||||||
|
handle.events = flags;
|
||||||
|
|
||||||
|
Ok(file)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result<usize> {
|
||||||
|
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
|
||||||
|
|
||||||
|
let path_string = format!("ip:{:X}", handle.proto);
|
||||||
|
let path = path_string.as_bytes();
|
||||||
|
|
||||||
|
let mut i = 0;
|
||||||
|
while i < buf.len() && i < path.len() {
|
||||||
|
buf[i] = path[i];
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fsync(&mut self, file: usize) -> Result<usize> {
|
||||||
|
let _handle = self.handles.get(&file).ok_or(Error::new(EBADF))?;
|
||||||
|
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn close(&mut self, file: usize) -> Result<usize> {
|
||||||
|
let handle = self.handles.remove(&file).ok_or(Error::new(EBADF))?;
|
||||||
|
|
||||||
|
drop(handle);
|
||||||
|
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
let mut socket = File::create(":ip").expect("ipd: failed to create 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 = IpScheme::new();
|
let scheme_file = unsafe { File::from_raw_fd(scheme_fd) };
|
||||||
loop {
|
|
||||||
let mut packet = Packet::default();
|
let ipd = Rc::new(RefCell::new(Ipd::new(scheme_file)));
|
||||||
socket.read(&mut packet).expect("ipd: failed to read events from ip scheme");
|
|
||||||
scheme.handle(&mut packet);
|
let mut event_queue = EventQueue::<()>::new().expect("ipd: failed to create event queue");
|
||||||
socket.write(&packet).expect("ipd: failed to write responses to ip scheme");
|
|
||||||
|
//TODO: Multiple interfaces
|
||||||
|
{
|
||||||
|
let arp_fd = syscall::open("ethernet:806", syscall::O_RDWR | syscall::O_NONBLOCK).expect("ipd: failed to open ethernet:806");
|
||||||
|
let ip_fd = syscall::open("ethernet:800", syscall::O_RDWR | syscall::O_NONBLOCK).expect("ipd: failed to open ethernet:800");
|
||||||
|
let if_id = {
|
||||||
|
let mut ipd = ipd.borrow_mut();
|
||||||
|
let if_id = ipd.interfaces.len();
|
||||||
|
ipd.interfaces.push(Interface::new(arp_fd, ip_fd));
|
||||||
|
if_id
|
||||||
|
};
|
||||||
|
|
||||||
|
let arp_ipd = ipd.clone();
|
||||||
|
event_queue.add(arp_fd, move |_count: usize| -> io::Result<Option<()>> {
|
||||||
|
arp_ipd.borrow_mut().arp_event(if_id)?;
|
||||||
|
Ok(None)
|
||||||
|
}).expect("ipd: failed to listen to events on ethernet:806");
|
||||||
|
|
||||||
|
let ip_ipd = ipd.clone();
|
||||||
|
event_queue.add(ip_fd, move |_count: usize| -> io::Result<Option<()>> {
|
||||||
|
ip_ipd.borrow_mut().ip_event(if_id)?;
|
||||||
|
Ok(None)
|
||||||
|
}).expect("ipd: failed to listen to events on ethernet:800");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
event_queue.add(scheme_fd, move |_count: usize| -> io::Result<Option<()>> {
|
||||||
|
ipd.borrow_mut().scheme_event()?;
|
||||||
|
Ok(None)
|
||||||
|
}).expect("ipd: failed to listen to events on :ip");
|
||||||
|
|
||||||
|
// Make sure that all descriptors are at EOF
|
||||||
|
event_queue.trigger_all(0).expect("ipd: failed to trigger event queue");
|
||||||
|
|
||||||
|
event_queue.run().expect("ipd: failed to run event queue");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
fn test() {
|
|
||||||
use scheme::IpScheme;
|
|
||||||
|
|
||||||
println!("* Test that we can read a simple packet from the same connection.");
|
|
||||||
let bytes = "TEST".as_bytes();
|
|
||||||
let mut scheme = IpScheme::new();
|
|
||||||
let a = scheme.open(&"ip:127.0.0.1/11".as_bytes(), 0, 0, 0).unwrap();
|
|
||||||
let num_bytes_written = scheme.write(a, bytes).unwrap();
|
|
||||||
assert_eq!(num_bytes_written, bytes.len());
|
|
||||||
|
|
||||||
let mut buf = [0;65536];
|
|
||||||
let num_bytes_read = scheme.read(a, &mut buf).unwrap();
|
|
||||||
assert_eq!(num_bytes_read, num_bytes_written);
|
|
||||||
|
|
||||||
let bytes_read = &buf[0..num_bytes_read];
|
|
||||||
assert_eq!(bytes, bytes_read);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
println!("* Test that the loopback is now empty.");
|
|
||||||
let num_bytes_read = scheme.read(a, &mut buf).unwrap();
|
|
||||||
assert_eq!(num_bytes_read, 0);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
println!("* Test that we can read the same packet from a different connection.");
|
|
||||||
let num_bytes_written = scheme.write(a, bytes).unwrap();
|
|
||||||
assert_eq!(num_bytes_written, bytes.len());
|
|
||||||
|
|
||||||
let b = scheme.open("ip:127.0.0.1/11".as_bytes(), 0, 0, 0).unwrap();
|
|
||||||
|
|
||||||
let num_bytes_read = scheme.read(b, &mut buf).unwrap();
|
|
||||||
assert_eq!(num_bytes_read, num_bytes_written);
|
|
||||||
|
|
||||||
let bytes_read = &buf[0..num_bytes_read];
|
|
||||||
assert_eq!(bytes, bytes_read);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
println!("* Test that the loopback is now empty for both connections.");
|
|
||||||
|
|
||||||
let num_bytes_read = scheme.read(a, &mut buf).unwrap();
|
|
||||||
assert_eq!(num_bytes_read, 0);
|
|
||||||
|
|
||||||
let num_bytes_read = scheme.read(b, &mut buf).unwrap();
|
|
||||||
assert_eq!(num_bytes_read, 0);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
println!("* Push a number of packets, check that we get them in the right order.");
|
|
||||||
let mut payloads : Vec<String> = (0..100).map(|i| format!("TEST {}", i)).collect();
|
|
||||||
for payload in &payloads {
|
|
||||||
let bytes = payload.into_bytes();
|
|
||||||
let num_bytes_written = scheme.write(a, &bytes).unwrap();
|
|
||||||
assert_eq!(bytes.len(), num_bytes_written);
|
|
||||||
}
|
|
||||||
for payload in &payloads {
|
|
||||||
let bytes = payload.into_bytes();
|
|
||||||
let mut buf = [0;65536];
|
|
||||||
let num_bytes_read = scheme.read(a, &mut buf).unwrap();
|
|
||||||
assert_eq!(bytes.len(), num_bytes_read);
|
|
||||||
let bytes_read = &buf[0..num_bytes_read];
|
|
||||||
assert_eq!(bytes, bytes_read);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,242 +0,0 @@
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::{cmp, mem};
|
|
||||||
use std::collections::VecDeque;
|
|
||||||
use std::rc::Rc;
|
|
||||||
use std::sync::Mutex;
|
|
||||||
|
|
||||||
use netutils::{n16, Ipv4Addr, Checksum, Ipv4Header, Ipv4};
|
|
||||||
use resource_scheme::Resource;
|
|
||||||
use syscall;
|
|
||||||
use syscall::error::*;
|
|
||||||
|
|
||||||
/// Max number of bytes in a packet.
|
|
||||||
const MAX_PACKET_LENGTH : usize = 65536;
|
|
||||||
|
|
||||||
/// A IP (internet protocol) resource.
|
|
||||||
///
|
|
||||||
/// Each instance represents a connection (~ a IP socket).
|
|
||||||
pub struct IpResource {
|
|
||||||
/// The underlying mechanism ensured to connect to the peer.
|
|
||||||
pub connection: Connection,
|
|
||||||
|
|
||||||
/// The IP address of the host (i.e. this machine).
|
|
||||||
pub host_addr: Ipv4Addr,
|
|
||||||
|
|
||||||
/// The IP address of the peer (i.e. the other machine).
|
|
||||||
pub peer_addr: Ipv4Addr,
|
|
||||||
|
|
||||||
/// The IP protocol used by this connection. See
|
|
||||||
/// http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml
|
|
||||||
/// for the list of valid protocols.
|
|
||||||
pub proto: u8,
|
|
||||||
|
|
||||||
/// The id of the next packet being sent.
|
|
||||||
/// See https://en.wikipedia.org/wiki/IPv4#Identification .
|
|
||||||
pub id: u16,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum Connection {
|
|
||||||
Device {
|
|
||||||
/// Link to the underlying device (typically, an Ethernet card).
|
|
||||||
link: usize,
|
|
||||||
|
|
||||||
/// If this connection was opened waiting for a peer (i.e. `ip:/protocol`),
|
|
||||||
/// the data received when the peer actually connected. Otherwise, empty.
|
|
||||||
/// Emptied during the first call to `read()`.
|
|
||||||
init_data: Vec<u8>,
|
|
||||||
},
|
|
||||||
Loopback {
|
|
||||||
/// FIFO queue of packets written to the loopback and waiting to be read.
|
|
||||||
///
|
|
||||||
/// The data stored contains the exact data that has been added by the client
|
|
||||||
/// calling `write()`, without adding any headers.
|
|
||||||
///
|
|
||||||
/// This buffer is shared between all loopback connections.
|
|
||||||
packets: Rc<RefCell<VecDeque<Vec<u8>>>>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Resource for IpResource {
|
|
||||||
/// Duplicate the connection.
|
|
||||||
///
|
|
||||||
/// This duplicates both `self.link` and `self.init_data`.
|
|
||||||
///
|
|
||||||
/// # Errors
|
|
||||||
///
|
|
||||||
/// Fails if the `link` to the underlying device cannot be
|
|
||||||
/// duplicated.
|
|
||||||
fn dup(&self) -> Result<Box<Self>> {
|
|
||||||
use self::Connection::*;
|
|
||||||
let connection = match self.connection {
|
|
||||||
Loopback { ref packets }=> Loopback { packets: packets.clone() },
|
|
||||||
Device { link, ref init_data } => {
|
|
||||||
let link = try!(syscall::dup(link));
|
|
||||||
let init_data = init_data.clone();
|
|
||||||
Device {
|
|
||||||
link: link,
|
|
||||||
init_data: init_data
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Ok(Box::new(IpResource {
|
|
||||||
host_addr: self.host_addr,
|
|
||||||
peer_addr: self.peer_addr,
|
|
||||||
proto: self.proto,
|
|
||||||
id: self.id,
|
|
||||||
connection: connection,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the current path, as `ip:peer/protocol`, where `peer`
|
|
||||||
/// is the IPv4 address of the peer and `protocol` is the hex-based
|
|
||||||
/// number of the IP protocol used.
|
|
||||||
///
|
|
||||||
/// Note that the `peer` is specified even if the connection was initially
|
|
||||||
/// created as `ip:/protocol`.
|
|
||||||
fn path(&self, buf: &mut [u8]) -> Result<usize> {
|
|
||||||
let path_string = format!("ip:{}/{:X}", self.peer_addr.to_string(), self.proto);
|
|
||||||
let path = path_string.as_bytes();
|
|
||||||
|
|
||||||
for (b, p) in buf.iter_mut().zip(path.iter()) {
|
|
||||||
*b = *p;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(cmp::min(buf.len(), path.len()))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Read data from the device.
|
|
||||||
///
|
|
||||||
/// If some data has already been made available during the establishment
|
|
||||||
/// of the connection, this data is (entirely) read during the first call
|
|
||||||
/// to `read()`, without attempting to actually read from the device. This
|
|
||||||
/// can happen only if the connection was waiting for a remote peer to connect, i.e.
|
|
||||||
/// with a url `ip:/protocol`, without host.
|
|
||||||
///
|
|
||||||
/// If this connection is a loopback, oldest unread packet written is read.
|
|
||||||
///
|
|
||||||
/// # Errors
|
|
||||||
///
|
|
||||||
/// Fails if the call to `syscall::read()` fails for this device.
|
|
||||||
///
|
|
||||||
/// # Data loss
|
|
||||||
///
|
|
||||||
/// If `buf` is too small, *exceeding data is discarded*. To be sure that you read
|
|
||||||
/// all data, you should provide a 64kb `buf`.
|
|
||||||
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
|
|
||||||
use self::Connection::*;
|
|
||||||
match self.connection {
|
|
||||||
Loopback { ref packets }=> {
|
|
||||||
match packets.borrow_mut().pop_front() {
|
|
||||||
None => Ok(0),
|
|
||||||
Some(data) => {
|
|
||||||
for (b, d) in buf.iter_mut().zip(data.iter()) {
|
|
||||||
*b = *d;
|
|
||||||
}
|
|
||||||
// Note: We're discarding excess `data`.
|
|
||||||
Ok(cmp::min(buf.len(), data.len()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Device { ref mut init_data, link } => {
|
|
||||||
if !init_data.is_empty() {
|
|
||||||
let mut data: Vec<u8> = Vec::new();
|
|
||||||
mem::swap(init_data, &mut data);
|
|
||||||
|
|
||||||
for (b, d) in buf.iter_mut().zip(data.iter()) {
|
|
||||||
*b = *d;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Ok(cmp::min(buf.len(), data.len()));
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut bytes = [0; MAX_PACKET_LENGTH];
|
|
||||||
let count = try!(syscall::read(link, &mut bytes));
|
|
||||||
|
|
||||||
if let Some(packet) = Ipv4::from_bytes(&bytes[..count]) {
|
|
||||||
if packet.header.proto == self.proto &&
|
|
||||||
(packet.header.dst.equals(self.host_addr) || packet.header.dst.equals(Ipv4Addr::BROADCAST)) &&
|
|
||||||
(packet.header.src.equals(self.peer_addr) || self.peer_addr.equals(Ipv4Addr::BROADCAST)) {
|
|
||||||
for (b, d) in buf.iter_mut().zip(packet.data.iter()) {
|
|
||||||
*b = *d;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Ok(cmp::min(buf.len(), packet.data.len()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Send data to the peer.
|
|
||||||
///
|
|
||||||
/// # Errors
|
|
||||||
///
|
|
||||||
/// Fails if the call to `syscall::write()` fails for this device.
|
|
||||||
fn write(&mut self, buf: &[u8]) -> Result<usize> {
|
|
||||||
use self::Connection::*;
|
|
||||||
|
|
||||||
let ip_data = Vec::from(buf);
|
|
||||||
match self.connection {
|
|
||||||
Loopback { ref packets } => {
|
|
||||||
// Make sure that we're not going to store data that can't be read.
|
|
||||||
let buf =
|
|
||||||
if buf.len() > MAX_PACKET_LENGTH {
|
|
||||||
&buf[0..MAX_PACKET_LENGTH]
|
|
||||||
} else {
|
|
||||||
buf
|
|
||||||
};
|
|
||||||
packets.borrow_mut().push_back(buf.to_vec());
|
|
||||||
return Ok(buf.len())
|
|
||||||
}
|
|
||||||
Device { link, .. } => {
|
|
||||||
self.id += 1;
|
|
||||||
let mut ip = Ipv4 {
|
|
||||||
header: Ipv4Header {
|
|
||||||
ver_hlen: 0x40 | (mem::size_of::<Ipv4Header>() / 4 & 0xF) as u8, // No Options
|
|
||||||
services: 0,
|
|
||||||
len: n16::new((mem::size_of::<Ipv4Header>() + ip_data.len()) as u16), // No Options
|
|
||||||
id: n16::new(self.id),
|
|
||||||
flags_fragment: n16::new(0),
|
|
||||||
ttl: 128,
|
|
||||||
proto: self.proto,
|
|
||||||
checksum: Checksum { data: 0 },
|
|
||||||
src: self.host_addr,
|
|
||||||
dst: self.peer_addr,
|
|
||||||
},
|
|
||||||
options: Vec::new(),
|
|
||||||
data: ip_data,
|
|
||||||
};
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
let header_ptr: *const Ipv4Header = &ip.header;
|
|
||||||
ip.header.checksum.data =
|
|
||||||
Checksum::compile(Checksum::sum(header_ptr as usize, mem::size_of::<Ipv4Header>()) +
|
|
||||||
Checksum::sum(ip.options.as_ptr() as usize, ip.options.len()));
|
|
||||||
}
|
|
||||||
|
|
||||||
match syscall::write(link, &ip.to_bytes()) {
|
|
||||||
Ok(_) => Ok(buf.len()),
|
|
||||||
Err(err) => Err(err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sync(&mut self) -> Result<usize> {
|
|
||||||
if let Connection::Device { link, .. } = self.connection {
|
|
||||||
syscall::fsync(link)
|
|
||||||
} else {
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for IpResource {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
if let Connection::Device { link, .. } = self.connection {
|
|
||||||
let _ = syscall::close(link);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,193 +0,0 @@
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::collections::VecDeque;
|
|
||||||
use std::rand;
|
|
||||||
use std::rc::Rc;
|
|
||||||
use std::{str, u16};
|
|
||||||
|
|
||||||
use netutils::{getcfg, n16, MacAddr, Ipv4Addr, ArpHeader, Arp, Ipv4};
|
|
||||||
use resource_scheme::ResourceScheme;
|
|
||||||
use syscall;
|
|
||||||
use syscall::error::{Error, Result, EACCES, ENOENT, EINVAL};
|
|
||||||
use syscall::flag::O_RDWR;
|
|
||||||
|
|
||||||
use resource::*;
|
|
||||||
|
|
||||||
/// The IP address of the localhost.
|
|
||||||
const LOCALHOST: Ipv4Addr = Ipv4Addr { bytes: [127, 0, 0, 1] };
|
|
||||||
|
|
||||||
/// A ARP entry (MAC + IP)
|
|
||||||
pub struct ArpEntry {
|
|
||||||
ip: Ipv4Addr,
|
|
||||||
mac: MacAddr,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A IP scheme
|
|
||||||
pub struct IpScheme {
|
|
||||||
pub arp: RefCell<Vec<ArpEntry>>,
|
|
||||||
|
|
||||||
/// FIFO queue of packets written to the loopback and waiting to be read.
|
|
||||||
///
|
|
||||||
/// The data stored contains the exact data that has been added by the client
|
|
||||||
/// calling `write()`, without adding any headers.
|
|
||||||
///
|
|
||||||
/// This buffer is shared between all loopback connections.
|
|
||||||
pub loopback_fifo: Rc<RefCell<VecDeque<Vec<u8>>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IpScheme {
|
|
||||||
pub fn new() -> IpScheme {
|
|
||||||
IpScheme {
|
|
||||||
arp: RefCell::new(Vec::new()),
|
|
||||||
loopback_fifo: Rc::new(RefCell::new(VecDeque::new())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ResourceScheme<IpResource> for IpScheme {
|
|
||||||
fn open_resource(&self, url: &[u8], _flags: usize, uid: u32, _gid: u32) -> Result<Box<IpResource>> {
|
|
||||||
if uid == 0 {
|
|
||||||
let mac_addr = MacAddr::from_str(&getcfg("mac").map_err(|err| err.into_sys())?);
|
|
||||||
let ip_addr = Ipv4Addr::from_str(&getcfg("ip").map_err(|err| err.into_sys())?);
|
|
||||||
let ip_subnet = Ipv4Addr::from_str(&getcfg("ip_subnet").map_err(|err| err.into_sys())?);
|
|
||||||
let ip_router = Ipv4Addr::from_str(&getcfg("ip_router").map_err(|err| err.into_sys())?);
|
|
||||||
|
|
||||||
let path = try!(str::from_utf8(url).or(Err(Error::new(EINVAL))));
|
|
||||||
let mut parts = path.split('/');
|
|
||||||
if let Some(host_string) = parts.next() {
|
|
||||||
if let Some(proto_string) = parts.next() {
|
|
||||||
let proto = u8::from_str_radix(proto_string, 16).unwrap_or(0);
|
|
||||||
|
|
||||||
if ! host_string.is_empty() {
|
|
||||||
let peer_addr = Ipv4Addr::from_str(host_string);
|
|
||||||
let mut route_mac = MacAddr::BROADCAST;
|
|
||||||
|
|
||||||
if ! peer_addr.equals(Ipv4Addr::BROADCAST) {
|
|
||||||
if peer_addr.equals(LOCALHOST) {
|
|
||||||
return Ok(Box::new(IpResource {
|
|
||||||
connection: Connection::Loopback {
|
|
||||||
packets: self.loopback_fifo.clone()
|
|
||||||
},
|
|
||||||
host_addr: ip_addr,
|
|
||||||
peer_addr: peer_addr,
|
|
||||||
proto: proto,
|
|
||||||
id: (rand() % 65536) as u16,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut needs_routing = false;
|
|
||||||
|
|
||||||
for octet in 0..4 {
|
|
||||||
let me = ip_addr.bytes[octet];
|
|
||||||
let mask = ip_subnet.bytes[octet];
|
|
||||||
let them = peer_addr.bytes[octet];
|
|
||||||
if me & mask != them & mask {
|
|
||||||
needs_routing = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let route_addr = if needs_routing {
|
|
||||||
ip_router
|
|
||||||
} else {
|
|
||||||
peer_addr
|
|
||||||
};
|
|
||||||
|
|
||||||
for entry in self.arp.borrow().iter() {
|
|
||||||
if entry.ip.equals(route_addr) {
|
|
||||||
route_mac = entry.mac;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if route_mac.equals(MacAddr::BROADCAST) {
|
|
||||||
if let Ok(link) = syscall::open(&format!("ethernet:{}/806", &route_mac.to_string()), O_RDWR) {
|
|
||||||
let arp = Arp {
|
|
||||||
header: ArpHeader {
|
|
||||||
htype: n16::new(1),
|
|
||||||
ptype: n16::new(0x800),
|
|
||||||
hlen: 6,
|
|
||||||
plen: 4,
|
|
||||||
oper: n16::new(1),
|
|
||||||
src_mac: mac_addr,
|
|
||||||
src_ip: ip_addr,
|
|
||||||
dst_mac: route_mac,
|
|
||||||
dst_ip: route_addr,
|
|
||||||
},
|
|
||||||
data: Vec::new(),
|
|
||||||
};
|
|
||||||
|
|
||||||
match syscall::write(link, &arp.to_bytes()) {
|
|
||||||
Ok(_) => loop {
|
|
||||||
let mut bytes = [0; 65536];
|
|
||||||
match syscall::read(link, &mut bytes) {
|
|
||||||
Ok(count) => if let Some(packet) = Arp::from_bytes(&bytes[..count]) {
|
|
||||||
if packet.header.oper.get() == 2 &&
|
|
||||||
packet.header.src_ip.equals(route_addr) {
|
|
||||||
route_mac = packet.header.src_mac;
|
|
||||||
self.arp.borrow_mut().push(ArpEntry {
|
|
||||||
ip: route_addr,
|
|
||||||
mac: route_mac,
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(_) => (),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(err) => println!("IP: ARP Write Failed: {}", err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Ok(link) = syscall::open(&format!("ethernet:{}/800", &route_mac.to_string()), O_RDWR) {
|
|
||||||
return Ok(Box::new(IpResource {
|
|
||||||
connection: Connection::Device {
|
|
||||||
link: link,
|
|
||||||
init_data: Vec::new(),
|
|
||||||
},
|
|
||||||
host_addr: ip_addr,
|
|
||||||
peer_addr: peer_addr,
|
|
||||||
proto: proto,
|
|
||||||
id: (rand() % 65536) as u16,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
while let Ok(link) = syscall::open("ethernet:/800", O_RDWR) {
|
|
||||||
let mut bytes = [0; 65536];
|
|
||||||
// FIXME: Blocking call?
|
|
||||||
match syscall::read(link, &mut bytes) {
|
|
||||||
Ok(count) => {
|
|
||||||
if let Some(packet) = Ipv4::from_bytes(&bytes[..count]) {
|
|
||||||
if packet.header.proto == proto &&
|
|
||||||
(packet.header.dst.equals(ip_addr) || packet.header.dst.equals(Ipv4Addr::BROADCAST)) {
|
|
||||||
return Ok(Box::new(IpResource {
|
|
||||||
connection: Connection::Device {
|
|
||||||
link: link,
|
|
||||||
init_data: packet.data,
|
|
||||||
},
|
|
||||||
host_addr: ip_addr,
|
|
||||||
peer_addr: packet.header.src,
|
|
||||||
proto: proto,
|
|
||||||
id: (rand() % 65536) as u16,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(_) => break,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
println!("IP: No protocol provided");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
println!("IP: No host provided");
|
|
||||||
}
|
|
||||||
|
|
||||||
Err(Error::new(ENOENT))
|
|
||||||
} else {
|
|
||||||
Err(Error::new(EACCES))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 601c5685f058c9276d896262195b50c75a6d7a97
|
Subproject commit 1d554eda337b9d75a4c0b209c3b399b8f1148f35
|
|
@ -16,7 +16,7 @@ impl Scheme for RandScheme {
|
||||||
Ok(0)
|
Ok(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dup(&self, file: usize) -> Result<usize> {
|
fn dup(&self, file: usize, _buf: &[u8]) -> Result<usize> {
|
||||||
Ok(file)
|
Ok(file)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 3dcaad55fe6e82450c1691da5d515861a7deed0a
|
Subproject commit ec00f58d73de142332e80d097e32f3d93c2a33bf
|
|
@ -3,6 +3,7 @@ name = "tcpd"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
event = { path = "../../crates/event/" }
|
||||||
netutils = { path = "../../programs/netutils/" }
|
netutils = { path = "../../programs/netutils/" }
|
||||||
resource_scheme = { path = "../../crates/resource_scheme/" }
|
rand = { git = "https://github.com/redox-os/rand.git" }
|
||||||
syscall = { path = "../../syscall/" }
|
syscall = { path = "../../syscall/" }
|
||||||
|
|
|
@ -1,30 +1,680 @@
|
||||||
#![feature(rand)]
|
extern crate event;
|
||||||
|
|
||||||
extern crate netutils;
|
extern crate netutils;
|
||||||
extern crate resource_scheme;
|
extern crate rand;
|
||||||
extern crate syscall;
|
extern crate syscall;
|
||||||
|
|
||||||
|
use rand::{Rng, OsRng};
|
||||||
|
use std::collections::{BTreeMap, VecDeque};
|
||||||
|
use std::cell::RefCell;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{Read, Write};
|
use std::io::{self, Read, Write};
|
||||||
use std::thread;
|
use std::{mem, slice, str, thread};
|
||||||
|
use std::os::unix::io::FromRawFd;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
use resource_scheme::ResourceScheme;
|
use event::EventQueue;
|
||||||
use syscall::Packet;
|
use netutils::{n16, n32, Ipv4, Ipv4Addr, Ipv4Header, Tcp, TcpHeader, Checksum, TCP_FIN, TCP_SYN, TCP_RST, TCP_PSH, TCP_ACK};
|
||||||
|
use syscall::data::Packet;
|
||||||
|
use syscall::error::{Error, Result, EACCES, EADDRINUSE, EBADF, EINVAL, EISCONN, EMSGSIZE, ENOTCONN, EWOULDBLOCK};
|
||||||
|
use syscall::flag::{EVENT_READ, O_CREAT, O_RDWR, O_NONBLOCK};
|
||||||
|
use syscall::scheme::SchemeMut;
|
||||||
|
|
||||||
use scheme::TcpScheme;
|
fn parse_socket(socket: &str) -> (Ipv4Addr, u16) {
|
||||||
|
let mut socket_parts = socket.split(":");
|
||||||
|
let host = Ipv4Addr::from_str(socket_parts.next().unwrap_or(""));
|
||||||
|
let port = socket_parts.next().unwrap_or("").parse::<u16>().unwrap_or(0);
|
||||||
|
(host, port)
|
||||||
|
}
|
||||||
|
|
||||||
mod resource;
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
mod scheme;
|
enum State {
|
||||||
|
Listen,
|
||||||
|
SynSent,
|
||||||
|
SynReceived,
|
||||||
|
Established,
|
||||||
|
FinWait1,
|
||||||
|
FinWait2,
|
||||||
|
CloseWait,
|
||||||
|
Closing,
|
||||||
|
LastAck,
|
||||||
|
TimeWait,
|
||||||
|
Closed
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Handle {
|
||||||
|
local: (Ipv4Addr, u16),
|
||||||
|
remote: (Ipv4Addr, u16),
|
||||||
|
flags: usize,
|
||||||
|
events: usize,
|
||||||
|
state: State,
|
||||||
|
seq: u32,
|
||||||
|
ack: u32,
|
||||||
|
data: VecDeque<(Ipv4, Tcp)>,
|
||||||
|
todo_dup: VecDeque<Packet>,
|
||||||
|
todo_read: VecDeque<Packet>,
|
||||||
|
todo_write: VecDeque<Packet>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Handle {
|
||||||
|
fn is_connected(&self) -> bool {
|
||||||
|
self.remote.0 != Ipv4Addr::NULL && self.remote.1 != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_closed(&self) -> bool {
|
||||||
|
self.state == State::CloseWait || self.state == State::LastAck || self.state == State::TimeWait || self.state == State::Closed
|
||||||
|
}
|
||||||
|
|
||||||
|
fn matches(&self, ip: &Ipv4, tcp: &Tcp) -> bool {
|
||||||
|
// Local address not set or IP dst matches or is broadcast
|
||||||
|
(self.local.0 == Ipv4Addr::NULL || ip.header.dst == self.local.0 || ip.header.dst == Ipv4Addr::BROADCAST)
|
||||||
|
// Local port matches UDP dst
|
||||||
|
&& tcp.header.dst.get() == self.local.1
|
||||||
|
// Remote address not set or is broadcast, or IP src matches
|
||||||
|
&& (self.remote.0 == Ipv4Addr::NULL || self.remote.0 == Ipv4Addr::BROADCAST || ip.header.src == self.remote.0)
|
||||||
|
// Remote port not set or UDP src matches
|
||||||
|
&& (self.remote.1 == 0 || tcp.header.src.get() == self.remote.1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_tcp(&self, flags: u16, data: Vec<u8>) -> Tcp {
|
||||||
|
Tcp {
|
||||||
|
header: TcpHeader {
|
||||||
|
src: n16::new(self.local.1),
|
||||||
|
dst: n16::new(self.remote.1),
|
||||||
|
sequence: n32::new(self.seq),
|
||||||
|
ack_num: n32::new(self.ack),
|
||||||
|
flags: n16::new(((mem::size_of::<TcpHeader>() << 10) & 0xF000) as u16 | (flags & 0xFFF)),
|
||||||
|
window_size: n16::new(8192),
|
||||||
|
checksum: Checksum { data: 0 },
|
||||||
|
urgent_pointer: n16::new(0),
|
||||||
|
},
|
||||||
|
options: Vec::new(),
|
||||||
|
data: data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_ip(&self, id: u16, data: Vec<u8>) -> Ipv4 {
|
||||||
|
Ipv4 {
|
||||||
|
header: Ipv4Header {
|
||||||
|
ver_hlen: 0x45,
|
||||||
|
services: 0,
|
||||||
|
len: n16::new((data.len() + mem::size_of::<Ipv4Header>()) as u16),
|
||||||
|
id: n16::new(id),
|
||||||
|
flags_fragment: n16::new(0),
|
||||||
|
ttl: 127,
|
||||||
|
proto: 0x06,
|
||||||
|
checksum: Checksum { data: 0 },
|
||||||
|
src: self.local.0,
|
||||||
|
dst: self.remote.0
|
||||||
|
},
|
||||||
|
options: Vec::new(),
|
||||||
|
data: data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Tcpd {
|
||||||
|
scheme_file: File,
|
||||||
|
tcp_file: File,
|
||||||
|
ports: BTreeMap<u16, usize>,
|
||||||
|
next_id: usize,
|
||||||
|
handles: BTreeMap<usize, Handle>,
|
||||||
|
rng: OsRng,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Tcpd {
|
||||||
|
fn new(scheme_file: File, tcp_file: File) -> Self {
|
||||||
|
Tcpd {
|
||||||
|
scheme_file: scheme_file,
|
||||||
|
tcp_file: tcp_file,
|
||||||
|
ports: BTreeMap::new(),
|
||||||
|
next_id: 1,
|
||||||
|
handles: BTreeMap::new(),
|
||||||
|
rng: OsRng::new().expect("tcpd: failed to open RNG")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn scheme_event(&mut self) -> io::Result<()> {
|
||||||
|
loop {
|
||||||
|
let mut packet = Packet::default();
|
||||||
|
if self.scheme_file.read(&mut packet)? == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let a = packet.a;
|
||||||
|
self.handle(&mut packet);
|
||||||
|
if packet.a == (-EWOULDBLOCK) as usize {
|
||||||
|
if let Some(mut handle) = self.handles.get_mut(&packet.b) {
|
||||||
|
match a {
|
||||||
|
syscall::number::SYS_DUP => {
|
||||||
|
packet.a = a;
|
||||||
|
handle.todo_dup.push_back(packet);
|
||||||
|
},
|
||||||
|
syscall::number::SYS_READ => {
|
||||||
|
packet.a = a;
|
||||||
|
handle.todo_read.push_back(packet);
|
||||||
|
},
|
||||||
|
syscall::number::SYS_WRITE => {
|
||||||
|
packet.a = a;
|
||||||
|
handle.todo_write.push_back(packet);
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
self.scheme_file.write(&packet)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.scheme_file.write(&packet)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tcp_event(&mut self) -> io::Result<()> {
|
||||||
|
loop {
|
||||||
|
let mut bytes = [0; 65536];
|
||||||
|
let count = self.tcp_file.read(&mut bytes)?;
|
||||||
|
if count == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if let Some(ip) = Ipv4::from_bytes(&bytes[.. count]) {
|
||||||
|
if let Some(tcp) = Tcp::from_bytes(&ip.data) {
|
||||||
|
let mut closing = Vec::new();
|
||||||
|
let mut found_connection = false;
|
||||||
|
for (id, handle) in self.handles.iter_mut() {
|
||||||
|
if handle.state != State::Listen && handle.matches(&ip, &tcp) {
|
||||||
|
found_connection = true;
|
||||||
|
|
||||||
|
match handle.state {
|
||||||
|
State::SynReceived => if tcp.header.flags.get() & (TCP_SYN | TCP_ACK) == TCP_ACK && tcp.header.ack_num.get() == handle.seq {
|
||||||
|
handle.state = State::Established;
|
||||||
|
},
|
||||||
|
State::SynSent => if tcp.header.flags.get() & (TCP_SYN | TCP_ACK) == TCP_SYN | TCP_ACK && tcp.header.ack_num.get() == handle.seq {
|
||||||
|
handle.state = State::Established;
|
||||||
|
handle.ack = tcp.header.sequence.get() + 1;
|
||||||
|
|
||||||
|
let tcp = handle.create_tcp(TCP_ACK, Vec::new());
|
||||||
|
let ip = handle.create_ip(self.rng.gen(), tcp.to_bytes());
|
||||||
|
self.tcp_file.write(&ip.to_bytes())?;
|
||||||
|
},
|
||||||
|
State::Established => if tcp.header.flags.get() & (TCP_SYN | TCP_ACK) == TCP_ACK && tcp.header.ack_num.get() == handle.seq {
|
||||||
|
handle.ack = tcp.header.sequence.get();
|
||||||
|
|
||||||
|
if ! tcp.data.is_empty() {
|
||||||
|
handle.data.push_back((ip.clone(), tcp.clone()));
|
||||||
|
handle.ack += tcp.data.len() as u32;
|
||||||
|
|
||||||
|
let tcp = handle.create_tcp(TCP_ACK, Vec::new());
|
||||||
|
let ip = handle.create_ip(self.rng.gen(), tcp.to_bytes());
|
||||||
|
self.tcp_file.write(&ip.to_bytes())?;
|
||||||
|
} else if tcp.header.flags.get() & TCP_FIN == TCP_FIN {
|
||||||
|
handle.state = State::CloseWait;
|
||||||
|
|
||||||
|
handle.ack += 1;
|
||||||
|
|
||||||
|
let tcp = handle.create_tcp(TCP_ACK, Vec::new());
|
||||||
|
let ip = handle.create_ip(self.rng.gen(), tcp.to_bytes());
|
||||||
|
self.tcp_file.write(&ip.to_bytes())?;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
//TODO: Time wait
|
||||||
|
State::FinWait1 => if tcp.header.flags.get() & (TCP_SYN | TCP_ACK) == TCP_ACK && tcp.header.ack_num.get() == handle.seq {
|
||||||
|
handle.ack = tcp.header.sequence.get() + 1;
|
||||||
|
|
||||||
|
if tcp.header.flags.get() & TCP_FIN == TCP_FIN {
|
||||||
|
handle.state = State::TimeWait;
|
||||||
|
|
||||||
|
let tcp = handle.create_tcp(TCP_ACK, Vec::new());
|
||||||
|
let ip = handle.create_ip(self.rng.gen(), tcp.to_bytes());
|
||||||
|
self.tcp_file.write(&ip.to_bytes())?;
|
||||||
|
|
||||||
|
closing.push(*id);
|
||||||
|
} else {
|
||||||
|
handle.state = State::FinWait2;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State::FinWait2 => if tcp.header.flags.get() & (TCP_SYN | TCP_ACK | TCP_FIN) == TCP_ACK | TCP_FIN && tcp.header.ack_num.get() == handle.seq {
|
||||||
|
handle.ack = tcp.header.sequence.get() + 1;
|
||||||
|
|
||||||
|
handle.state = State::TimeWait;
|
||||||
|
|
||||||
|
let tcp = handle.create_tcp(TCP_ACK, Vec::new());
|
||||||
|
let ip = handle.create_ip(self.rng.gen(), tcp.to_bytes());
|
||||||
|
self.tcp_file.write(&ip.to_bytes())?;
|
||||||
|
|
||||||
|
closing.push(*id);
|
||||||
|
},
|
||||||
|
State::LastAck => if tcp.header.flags.get() & (TCP_SYN | TCP_ACK) == TCP_ACK && tcp.header.ack_num.get() == handle.seq {
|
||||||
|
handle.state = State::Closed;
|
||||||
|
closing.push(*id);
|
||||||
|
},
|
||||||
|
_ => ()
|
||||||
|
}
|
||||||
|
|
||||||
|
while ! handle.todo_read.is_empty() && (! handle.data.is_empty() || handle.read_closed()) {
|
||||||
|
let mut packet = handle.todo_read.pop_front().unwrap();
|
||||||
|
let buf = unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) };
|
||||||
|
if let Some((_ip, tcp)) = handle.data.pop_front() {
|
||||||
|
let mut i = 0;
|
||||||
|
while i < buf.len() && i < tcp.data.len() {
|
||||||
|
buf[i] = tcp.data[i];
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
packet.a = i;
|
||||||
|
} else {
|
||||||
|
packet.a = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.scheme_file.write(&packet)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ! handle.todo_write.is_empty() && handle.state == State::Established {
|
||||||
|
let mut packet = handle.todo_write.pop_front().unwrap();
|
||||||
|
let buf = unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) };
|
||||||
|
|
||||||
|
let tcp = handle.create_tcp(TCP_ACK | TCP_PSH, buf.to_vec());
|
||||||
|
let ip = handle.create_ip(self.rng.gen(), tcp.to_bytes());
|
||||||
|
let result = self.tcp_file.write(&ip.to_bytes()).map_err(|err| err.into_sys());
|
||||||
|
if result.is_ok() {
|
||||||
|
handle.seq += buf.len() as u32;
|
||||||
|
}
|
||||||
|
packet.a = Error::mux(result.and(Ok(buf.len())));
|
||||||
|
|
||||||
|
self.scheme_file.write(&packet)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if handle.events & EVENT_READ == EVENT_READ {
|
||||||
|
if let Some(&(ref _ip, ref tcp)) = handle.data.get(0) {
|
||||||
|
self.scheme_file.write(&Packet {
|
||||||
|
id: 0,
|
||||||
|
pid: 0,
|
||||||
|
uid: 0,
|
||||||
|
gid: 0,
|
||||||
|
a: syscall::number::SYS_FEVENT,
|
||||||
|
b: *id,
|
||||||
|
c: EVENT_READ,
|
||||||
|
d: tcp.data.len()
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for file in closing {
|
||||||
|
let handle = self.handles.remove(&file).unwrap();
|
||||||
|
|
||||||
|
let remove = if let Some(mut port) = self.ports.get_mut(&handle.local.1) {
|
||||||
|
*port = *port + 1;
|
||||||
|
*port == 0
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
|
if remove {
|
||||||
|
self.ports.remove(&handle.local.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ! found_connection && tcp.header.flags.get() & (TCP_SYN | TCP_ACK) == TCP_SYN {
|
||||||
|
let mut new_handles = Vec::new();
|
||||||
|
|
||||||
|
for (_id, handle) in self.handles.iter_mut() {
|
||||||
|
if handle.state == State::Listen && handle.matches(&ip, &tcp) {
|
||||||
|
handle.data.push_back((ip.clone(), tcp.clone()));
|
||||||
|
|
||||||
|
while ! handle.todo_dup.is_empty() && ! handle.data.is_empty() {
|
||||||
|
let mut packet = handle.todo_dup.pop_front().unwrap();
|
||||||
|
let (ip, tcp) = handle.data.pop_front().unwrap();
|
||||||
|
|
||||||
|
let mut new_handle = Handle {
|
||||||
|
local: handle.local,
|
||||||
|
remote: (ip.header.src, tcp.header.src.get()),
|
||||||
|
flags: handle.flags,
|
||||||
|
events: 0,
|
||||||
|
state: State::SynReceived,
|
||||||
|
seq: self.rng.gen(),
|
||||||
|
ack: tcp.header.sequence.get() + 1,
|
||||||
|
data: VecDeque::new(),
|
||||||
|
todo_dup: VecDeque::new(),
|
||||||
|
todo_read: VecDeque::new(),
|
||||||
|
todo_write: VecDeque::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let tcp = new_handle.create_tcp(TCP_SYN | TCP_ACK, Vec::new());
|
||||||
|
let ip = new_handle.create_ip(self.rng.gen(), tcp.to_bytes());
|
||||||
|
self.tcp_file.write(&ip.to_bytes())?;
|
||||||
|
|
||||||
|
new_handle.seq += 1;
|
||||||
|
|
||||||
|
handle.data.retain(|&(ref ip, ref tcp)| {
|
||||||
|
if new_handle.matches(ip, tcp) {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Some(mut port) = self.ports.get_mut(&handle.local.1) {
|
||||||
|
*port = *port + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let id = self.next_id;
|
||||||
|
self.next_id += 1;
|
||||||
|
|
||||||
|
packet.a = id;
|
||||||
|
|
||||||
|
new_handles.push((packet, new_handle));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (packet, new_handle) in new_handles {
|
||||||
|
self.handles.insert(packet.a, new_handle);
|
||||||
|
self.scheme_file.write(&packet)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SchemeMut for Tcpd {
|
||||||
|
fn open(&mut self, url: &[u8], flags: usize, uid: u32, _gid: u32) -> Result<usize> {
|
||||||
|
let path = str::from_utf8(url).or(Err(Error::new(EINVAL)))?;
|
||||||
|
|
||||||
|
let mut parts = path.split("/");
|
||||||
|
let remote = parse_socket(parts.next().unwrap_or(""));
|
||||||
|
let mut local = parse_socket(parts.next().unwrap_or(""));
|
||||||
|
|
||||||
|
if local.1 == 0 {
|
||||||
|
local.1 = self.rng.gen_range(32768, 65535);
|
||||||
|
}
|
||||||
|
|
||||||
|
if local.1 <= 1024 && uid != 0 {
|
||||||
|
return Err(Error::new(EACCES));
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.ports.contains_key(&local.1) {
|
||||||
|
return Err(Error::new(EADDRINUSE));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut handle = Handle {
|
||||||
|
local: local,
|
||||||
|
remote: remote,
|
||||||
|
flags: flags,
|
||||||
|
events: 0,
|
||||||
|
state: State::Listen,
|
||||||
|
seq: 0,
|
||||||
|
ack: 0,
|
||||||
|
data: VecDeque::new(),
|
||||||
|
todo_dup: VecDeque::new(),
|
||||||
|
todo_read: VecDeque::new(),
|
||||||
|
todo_write: VecDeque::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if handle.is_connected() {
|
||||||
|
handle.seq = self.rng.gen();
|
||||||
|
handle.ack = 0;
|
||||||
|
handle.state = State::SynSent;
|
||||||
|
|
||||||
|
let tcp = handle.create_tcp(TCP_SYN, Vec::new());
|
||||||
|
let ip = handle.create_ip(self.rng.gen(), tcp.to_bytes());
|
||||||
|
self.tcp_file.write(&ip.to_bytes()).map_err(|err| err.into_sys())?;
|
||||||
|
|
||||||
|
handle.seq += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.ports.insert(local.1, 1);
|
||||||
|
|
||||||
|
let id = self.next_id;
|
||||||
|
self.next_id += 1;
|
||||||
|
|
||||||
|
self.handles.insert(id, handle);
|
||||||
|
|
||||||
|
Ok(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dup(&mut self, file: usize, buf: &[u8]) -> Result<usize> {
|
||||||
|
let path = str::from_utf8(buf).or(Err(Error::new(EINVAL)))?;
|
||||||
|
|
||||||
|
let handle = {
|
||||||
|
let mut handle = self.handles.get_mut(&file).ok_or(Error::new(EBADF))?;
|
||||||
|
|
||||||
|
let mut new_handle = Handle {
|
||||||
|
local: handle.local,
|
||||||
|
remote: handle.remote,
|
||||||
|
flags: handle.flags,
|
||||||
|
events: 0,
|
||||||
|
state: handle.state,
|
||||||
|
seq: handle.seq,
|
||||||
|
ack: handle.ack,
|
||||||
|
data: VecDeque::new(),
|
||||||
|
todo_dup: VecDeque::new(),
|
||||||
|
todo_read: VecDeque::new(),
|
||||||
|
todo_write: VecDeque::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if path == "listen" {
|
||||||
|
if handle.is_connected() {
|
||||||
|
return Err(Error::new(EISCONN));
|
||||||
|
} else if let Some((ip, tcp)) = handle.data.pop_front() {
|
||||||
|
new_handle.remote = (ip.header.src, tcp.header.src.get());
|
||||||
|
|
||||||
|
new_handle.seq = self.rng.gen();
|
||||||
|
new_handle.ack = tcp.header.sequence.get() + 1;
|
||||||
|
new_handle.state = State::SynReceived;
|
||||||
|
|
||||||
|
let tcp = new_handle.create_tcp(TCP_SYN | TCP_ACK, Vec::new());
|
||||||
|
let ip = new_handle.create_ip(self.rng.gen(), tcp.to_bytes());
|
||||||
|
self.tcp_file.write(&ip.to_bytes()).map_err(|err| err.into_sys()).and(Ok(buf.len()))?;
|
||||||
|
|
||||||
|
new_handle.seq += 1;
|
||||||
|
} else {
|
||||||
|
return Err(Error::new(EWOULDBLOCK));
|
||||||
|
}
|
||||||
|
|
||||||
|
handle.data.retain(|&(ref ip, ref tcp)| {
|
||||||
|
if new_handle.matches(ip, tcp) {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if path.is_empty() {
|
||||||
|
new_handle.data = handle.data.clone();
|
||||||
|
} else if handle.is_connected() {
|
||||||
|
return Err(Error::new(EISCONN));
|
||||||
|
} else {
|
||||||
|
new_handle.remote = parse_socket(path);
|
||||||
|
|
||||||
|
if new_handle.is_connected() {
|
||||||
|
new_handle.seq = self.rng.gen();
|
||||||
|
new_handle.ack = 0;
|
||||||
|
new_handle.state = State::SynSent;
|
||||||
|
|
||||||
|
handle.data.retain(|&(ref ip, ref tcp)| {
|
||||||
|
if new_handle.matches(ip, tcp) {
|
||||||
|
new_handle.data.push_back((ip.clone(), tcp.clone()));
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let tcp = new_handle.create_tcp(TCP_SYN, Vec::new());
|
||||||
|
let ip = new_handle.create_ip(self.rng.gen(), tcp.to_bytes());
|
||||||
|
self.tcp_file.write(&ip.to_bytes()).map_err(|err| err.into_sys()).and(Ok(buf.len()))?;
|
||||||
|
} else {
|
||||||
|
return Err(Error::new(EINVAL));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
new_handle
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(mut port) = self.ports.get_mut(&handle.local.1) {
|
||||||
|
*port = *port + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let id = self.next_id;
|
||||||
|
self.next_id += 1;
|
||||||
|
|
||||||
|
self.handles.insert(id, handle);
|
||||||
|
|
||||||
|
Ok(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read(&mut self, file: usize, buf: &mut [u8]) -> Result<usize> {
|
||||||
|
let mut handle = self.handles.get_mut(&file).ok_or(Error::new(EBADF))?;
|
||||||
|
|
||||||
|
if ! handle.is_connected() {
|
||||||
|
Err(Error::new(ENOTCONN))
|
||||||
|
} else if let Some((_ip, tcp)) = handle.data.pop_front() {
|
||||||
|
let mut i = 0;
|
||||||
|
while i < buf.len() && i < tcp.data.len() {
|
||||||
|
buf[i] = tcp.data[i];
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(i)
|
||||||
|
} else if handle.flags & O_NONBLOCK == O_NONBLOCK || handle.read_closed() {
|
||||||
|
Ok(0)
|
||||||
|
} else {
|
||||||
|
Err(Error::new(EWOULDBLOCK))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(&mut self, file: usize, buf: &[u8]) -> Result<usize> {
|
||||||
|
let mut handle = self.handles.get_mut(&file).ok_or(Error::new(EBADF))?;
|
||||||
|
|
||||||
|
if ! handle.is_connected() {
|
||||||
|
Err(Error::new(ENOTCONN))
|
||||||
|
} else if buf.len() >= 65507 {
|
||||||
|
Err(Error::new(EMSGSIZE))
|
||||||
|
} else {
|
||||||
|
match handle.state {
|
||||||
|
State::Established => {
|
||||||
|
let tcp = handle.create_tcp(TCP_ACK | TCP_PSH, buf.to_vec());
|
||||||
|
let ip = handle.create_ip(self.rng.gen(), tcp.to_bytes());
|
||||||
|
self.tcp_file.write(&ip.to_bytes()).map_err(|err| err.into_sys())?;
|
||||||
|
handle.seq += buf.len() as u32;
|
||||||
|
Ok(buf.len())
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
Err(Error::new(EWOULDBLOCK))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fevent(&mut self, file: usize, flags: usize) -> Result<usize> {
|
||||||
|
let mut handle = self.handles.get_mut(&file).ok_or(Error::new(EBADF))?;
|
||||||
|
|
||||||
|
handle.events = flags;
|
||||||
|
|
||||||
|
Ok(file)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result<usize> {
|
||||||
|
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
|
||||||
|
|
||||||
|
let path_string = format!("tcp:{}:{}/{}:{}", handle.remote.0.to_string(), handle.remote.1, handle.local.0.to_string(), handle.local.1);
|
||||||
|
let path = path_string.as_bytes();
|
||||||
|
|
||||||
|
let mut i = 0;
|
||||||
|
while i < buf.len() && i < path.len() {
|
||||||
|
buf[i] = path[i];
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fsync(&mut self, file: usize) -> Result<usize> {
|
||||||
|
let _handle = self.handles.get(&file).ok_or(Error::new(EBADF))?;
|
||||||
|
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn close(&mut self, file: usize) -> Result<usize> {
|
||||||
|
|
||||||
|
let closed = {
|
||||||
|
let mut handle = self.handles.get_mut(&file).ok_or(Error::new(EBADF))?;
|
||||||
|
|
||||||
|
match handle.state {
|
||||||
|
State::SynReceived | State::Established => {
|
||||||
|
handle.state = State::FinWait1;
|
||||||
|
|
||||||
|
let tcp = handle.create_tcp(TCP_FIN | TCP_ACK, Vec::new());
|
||||||
|
let ip = handle.create_ip(self.rng.gen(), tcp.to_bytes());
|
||||||
|
self.tcp_file.write(&ip.to_bytes()).map_err(|err| err.into_sys())?;
|
||||||
|
|
||||||
|
handle.seq += 1;
|
||||||
|
|
||||||
|
false
|
||||||
|
},
|
||||||
|
State::CloseWait => {
|
||||||
|
handle.state = State::LastAck;
|
||||||
|
|
||||||
|
let tcp = handle.create_tcp(TCP_FIN | TCP_ACK, Vec::new());
|
||||||
|
let ip = handle.create_ip(self.rng.gen(), tcp.to_bytes());
|
||||||
|
self.tcp_file.write(&ip.to_bytes()).map_err(|err| err.into_sys())?;
|
||||||
|
|
||||||
|
handle.seq += 1;
|
||||||
|
|
||||||
|
false
|
||||||
|
},
|
||||||
|
_ => true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if closed {
|
||||||
|
let handle = self.handles.remove(&file).ok_or(Error::new(EBADF))?;
|
||||||
|
|
||||||
|
let remove = if let Some(mut port) = self.ports.get_mut(&handle.local.1) {
|
||||||
|
*port = *port + 1;
|
||||||
|
*port == 0
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
|
if remove {
|
||||||
|
self.ports.remove(&handle.local.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
let mut socket = File::create(":tcp").expect("tcpd: failed to create tcp scheme");
|
let scheme_fd = syscall::open(":tcp", O_RDWR | O_CREAT | O_NONBLOCK).expect("tcpd: failed to create :tcp");
|
||||||
let scheme = TcpScheme;
|
let scheme_file = unsafe { File::from_raw_fd(scheme_fd) };
|
||||||
loop {
|
|
||||||
let mut packet = Packet::default();
|
let tcp_fd = syscall::open("ip:6", O_RDWR | O_NONBLOCK).expect("tcpd: failed to open ip:6");
|
||||||
socket.read(&mut packet).expect("tcpd: failed to read events from tcp scheme");
|
let tcp_file = unsafe { File::from_raw_fd(tcp_fd) };
|
||||||
scheme.handle(&mut packet);
|
|
||||||
socket.write(&packet).expect("tcpd: failed to write responses to tcp scheme");
|
let tcpd = Rc::new(RefCell::new(Tcpd::new(scheme_file, tcp_file)));
|
||||||
}
|
|
||||||
|
let mut event_queue = EventQueue::<()>::new().expect("tcpd: failed to create event queue");
|
||||||
|
|
||||||
|
let tcp_tcpd = tcpd.clone();
|
||||||
|
event_queue.add(tcp_fd, move |_count: usize| -> io::Result<Option<()>> {
|
||||||
|
tcp_tcpd.borrow_mut().tcp_event()?;
|
||||||
|
Ok(None)
|
||||||
|
}).expect("tcpd: failed to listen to events on ip:6");
|
||||||
|
|
||||||
|
event_queue.add(scheme_fd, move |_count: usize| -> io::Result<Option<()>> {
|
||||||
|
tcpd.borrow_mut().scheme_event()?;
|
||||||
|
Ok(None)
|
||||||
|
}).expect("tcpd: failed to listen to events on :tcp");
|
||||||
|
|
||||||
|
event_queue.trigger_all(0).expect("tcpd: failed to trigger event queue");
|
||||||
|
|
||||||
|
event_queue.run().expect("tcpd: failed to run event queue");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,328 +0,0 @@
|
||||||
use std::{cmp, mem};
|
|
||||||
use std::cell::UnsafeCell;
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use netutils::{n16, n32, Ipv4Addr, Checksum, Tcp, TcpHeader, TCP_SYN, TCP_PSH, TCP_FIN, TCP_ACK};
|
|
||||||
use resource_scheme::Resource;
|
|
||||||
use syscall;
|
|
||||||
use syscall::error::*;
|
|
||||||
|
|
||||||
pub struct TcpStream {
|
|
||||||
pub ip: usize,
|
|
||||||
pub host_addr: Ipv4Addr,
|
|
||||||
pub peer_addr: Ipv4Addr,
|
|
||||||
pub peer_port: u16,
|
|
||||||
pub host_port: u16,
|
|
||||||
pub sequence: u32,
|
|
||||||
pub acknowledge: u32,
|
|
||||||
pub finished: bool
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TcpStream {
|
|
||||||
fn path(&self, buf: &mut [u8]) -> Result<usize> {
|
|
||||||
let path_string = format!("tcp:{}:{}/{}", self.peer_addr.to_string(), self.peer_port, self.host_port);
|
|
||||||
let path = path_string.as_bytes();
|
|
||||||
|
|
||||||
for (b, p) in buf.iter_mut().zip(path.iter()) {
|
|
||||||
*b = *p;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(cmp::min(buf.len(), path.len()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
|
|
||||||
if self.finished {
|
|
||||||
return Ok(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
loop {
|
|
||||||
let mut bytes = [0; 65536];
|
|
||||||
let count = try!(syscall::read(self.ip, &mut bytes));
|
|
||||||
|
|
||||||
if let Some(segment) = Tcp::from_bytes(&bytes[..count]) {
|
|
||||||
if segment.header.dst.get() == self.host_port && segment.header.src.get() == self.peer_port {
|
|
||||||
//println!("Read: {}=={} {:X}: {}", segment.header.sequence.get(), self.acknowledge, segment.header.flags.get(), segment.data.len());
|
|
||||||
|
|
||||||
if self.acknowledge == segment.header.sequence.get() {
|
|
||||||
if segment.header.flags.get() & TCP_FIN == TCP_FIN {
|
|
||||||
self.finished = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if segment.header.flags.get() & (TCP_SYN | TCP_ACK) == TCP_ACK {
|
|
||||||
let flags = if self.finished {
|
|
||||||
TCP_ACK | TCP_FIN
|
|
||||||
} else {
|
|
||||||
TCP_ACK
|
|
||||||
};
|
|
||||||
|
|
||||||
// Send ACK
|
|
||||||
self.acknowledge += segment.data.len() as u32;
|
|
||||||
let mut tcp = Tcp {
|
|
||||||
header: TcpHeader {
|
|
||||||
src: n16::new(self.host_port),
|
|
||||||
dst: n16::new(self.peer_port),
|
|
||||||
sequence: n32::new(self.sequence),
|
|
||||||
ack_num: n32::new(self.acknowledge),
|
|
||||||
flags: n16::new(((mem::size_of::<TcpHeader>() << 10) & 0xF000) as u16 | flags),
|
|
||||||
window_size: n16::new(65535),
|
|
||||||
checksum: Checksum {
|
|
||||||
data: 0
|
|
||||||
},
|
|
||||||
urgent_pointer: n16::new(0)
|
|
||||||
},
|
|
||||||
options: Vec::new(),
|
|
||||||
data: Vec::new()
|
|
||||||
};
|
|
||||||
|
|
||||||
tcp.checksum(&self.host_addr, &self.peer_addr);
|
|
||||||
|
|
||||||
//println!("Sending read ack: {} {} {:X}", tcp.header.sequence.get(), tcp.header.ack_num.get(), tcp.header.flags.get());
|
|
||||||
|
|
||||||
let _ = syscall::write(self.ip, &tcp.to_bytes());
|
|
||||||
|
|
||||||
// TODO: Support broken packets (one packet in two buffers)
|
|
||||||
let mut i = 0;
|
|
||||||
while i < buf.len() && i < segment.data.len() {
|
|
||||||
buf[i] = segment.data[i];
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
return Ok(i);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
println!("TCP: MISMATCH: {}=={}", segment.header.sequence.get(), self.acknowledge);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
println!("TCP: WRONG PORT {}=={} && {}=={}", segment.header.dst.get(), self.host_port, segment.header.src.get(), self.peer_port);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write(&mut self, buf: &[u8]) -> Result<usize> {
|
|
||||||
let tcp_data = Vec::from(buf);
|
|
||||||
|
|
||||||
let mut tcp = Tcp {
|
|
||||||
header: TcpHeader {
|
|
||||||
src: n16::new(self.host_port),
|
|
||||||
dst: n16::new(self.peer_port),
|
|
||||||
sequence: n32::new(self.sequence),
|
|
||||||
ack_num: n32::new(self.acknowledge),
|
|
||||||
flags: n16::new((((mem::size_of::<TcpHeader>()) << 10) & 0xF000) as u16 | TCP_PSH |
|
|
||||||
TCP_ACK),
|
|
||||||
window_size: n16::new(65535),
|
|
||||||
checksum: Checksum { data: 0 },
|
|
||||||
urgent_pointer: n16::new(0),
|
|
||||||
},
|
|
||||||
options: Vec::new(),
|
|
||||||
data: tcp_data,
|
|
||||||
};
|
|
||||||
|
|
||||||
tcp.checksum(&self.host_addr, &self.peer_addr);
|
|
||||||
|
|
||||||
match syscall::write(self.ip, &tcp.to_bytes()) {
|
|
||||||
Ok(size) => {
|
|
||||||
loop {
|
|
||||||
// Wait for ACK
|
|
||||||
let mut bytes = [0; 65536];
|
|
||||||
match syscall::read(self.ip, &mut bytes) {
|
|
||||||
Ok(count) => {
|
|
||||||
if let Some(segment) = Tcp::from_bytes(&bytes[..count]) {
|
|
||||||
if segment.header.dst.get() == self.host_port &&
|
|
||||||
segment.header.src.get() == self.peer_port {
|
|
||||||
return if (segment.header.flags.get() & (TCP_SYN | TCP_ACK)) == TCP_ACK {
|
|
||||||
self.sequence = segment.header.ack_num.get();
|
|
||||||
self.acknowledge = segment.header.sequence.get();
|
|
||||||
Ok(size)
|
|
||||||
} else {
|
|
||||||
Err(Error::new(EPIPE))
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(err) => return Err(err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(err) => Err(err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sync(&mut self) -> Result<usize> {
|
|
||||||
syscall::fsync(self.ip)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Etablish client
|
|
||||||
pub fn client_establish(&mut self) -> bool {
|
|
||||||
// Send SYN
|
|
||||||
let mut tcp = Tcp {
|
|
||||||
header: TcpHeader {
|
|
||||||
src: n16::new(self.host_port),
|
|
||||||
dst: n16::new(self.peer_port),
|
|
||||||
sequence: n32::new(self.sequence),
|
|
||||||
ack_num: n32::new(self.acknowledge),
|
|
||||||
flags: n16::new(((mem::size_of::<TcpHeader>() << 10) & 0xF000) as u16 | TCP_SYN),
|
|
||||||
window_size: n16::new(65535),
|
|
||||||
checksum: Checksum { data: 0 },
|
|
||||||
urgent_pointer: n16::new(0),
|
|
||||||
},
|
|
||||||
options: Vec::new(),
|
|
||||||
data: Vec::new(),
|
|
||||||
};
|
|
||||||
|
|
||||||
tcp.checksum(&self.host_addr, &self.peer_addr);
|
|
||||||
|
|
||||||
match syscall::write(self.ip, &tcp.to_bytes()) {
|
|
||||||
Ok(_) => {
|
|
||||||
loop {
|
|
||||||
// Wait for SYN-ACK
|
|
||||||
let mut bytes = [0; 65536];
|
|
||||||
match syscall::read(self.ip, &mut bytes) {
|
|
||||||
Ok(count) => {
|
|
||||||
if let Some(segment) = Tcp::from_bytes(&bytes[..count]) {
|
|
||||||
if segment.header.dst.get() == self.host_port &&
|
|
||||||
segment.header.src.get() == self.peer_port {
|
|
||||||
return if segment.header.flags.get() & (TCP_SYN | TCP_ACK) == TCP_SYN | TCP_ACK {
|
|
||||||
self.sequence = segment.header.ack_num.get();
|
|
||||||
self.acknowledge = segment.header.sequence.get();
|
|
||||||
|
|
||||||
self.acknowledge += 1;
|
|
||||||
tcp = Tcp {
|
|
||||||
header: TcpHeader {
|
|
||||||
src: n16::new(self.host_port),
|
|
||||||
dst: n16::new(self.peer_port),
|
|
||||||
sequence: n32::new(self.sequence),
|
|
||||||
ack_num: n32::new(self.acknowledge),
|
|
||||||
flags: n16::new(((mem::size_of::<TcpHeader>() << 10) & 0xF000) as u16 | TCP_ACK),
|
|
||||||
window_size: n16::new(65535),
|
|
||||||
checksum: Checksum {
|
|
||||||
data: 0
|
|
||||||
},
|
|
||||||
urgent_pointer: n16::new(0)
|
|
||||||
},
|
|
||||||
options: Vec::new(),
|
|
||||||
data: Vec::new()
|
|
||||||
};
|
|
||||||
|
|
||||||
tcp.checksum(&self.host_addr, &self.peer_addr);
|
|
||||||
|
|
||||||
let _ = syscall::write(self.ip, &tcp.to_bytes());
|
|
||||||
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(_) => return false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(_) => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Try to establish a server connection
|
|
||||||
pub fn server_establish(&mut self, _: Tcp) -> bool {
|
|
||||||
// Send SYN-ACK
|
|
||||||
self.acknowledge += 1;
|
|
||||||
let mut tcp = Tcp {
|
|
||||||
header: TcpHeader {
|
|
||||||
src: n16::new(self.host_port),
|
|
||||||
dst: n16::new(self.peer_port),
|
|
||||||
sequence: n32::new(self.sequence),
|
|
||||||
ack_num: n32::new(self.acknowledge),
|
|
||||||
flags: n16::new(((mem::size_of::<TcpHeader>() << 10) & 0xF000) as u16 | TCP_SYN |
|
|
||||||
TCP_ACK),
|
|
||||||
window_size: n16::new(65535),
|
|
||||||
checksum: Checksum { data: 0 },
|
|
||||||
urgent_pointer: n16::new(0),
|
|
||||||
},
|
|
||||||
options: Vec::new(),
|
|
||||||
data: Vec::new(),
|
|
||||||
};
|
|
||||||
|
|
||||||
tcp.checksum(&self.host_addr, &self.peer_addr);
|
|
||||||
|
|
||||||
match syscall::write(self.ip, &tcp.to_bytes()) {
|
|
||||||
Ok(_) => {
|
|
||||||
loop {
|
|
||||||
// Wait for ACK
|
|
||||||
let mut bytes = [0; 65536];
|
|
||||||
match syscall::read(self.ip, &mut bytes) {
|
|
||||||
Ok(count ) => {
|
|
||||||
if let Some(segment) = Tcp::from_bytes(&bytes[..count]) {
|
|
||||||
if segment.header.dst.get() == self.host_port &&
|
|
||||||
segment.header.src.get() == self.peer_port {
|
|
||||||
return if segment.header.flags.get() & (TCP_SYN | TCP_ACK) == TCP_ACK {
|
|
||||||
self.sequence = segment.header.ack_num.get();
|
|
||||||
self.acknowledge = segment.header.sequence.get();
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(_) => return false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(_) => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for TcpStream {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
// Send FIN-ACK
|
|
||||||
let mut tcp = Tcp {
|
|
||||||
header: TcpHeader {
|
|
||||||
src: n16::new(self.host_port),
|
|
||||||
dst: n16::new(self.peer_port),
|
|
||||||
sequence: n32::new(self.sequence),
|
|
||||||
ack_num: n32::new(self.acknowledge),
|
|
||||||
flags: n16::new((((mem::size_of::<TcpHeader>()) << 10) & 0xF000) as u16 | TCP_FIN | TCP_ACK),
|
|
||||||
window_size: n16::new(65535),
|
|
||||||
checksum: Checksum { data: 0 },
|
|
||||||
urgent_pointer: n16::new(0),
|
|
||||||
},
|
|
||||||
options: Vec::new(),
|
|
||||||
data: Vec::new(),
|
|
||||||
};
|
|
||||||
|
|
||||||
tcp.checksum(&self.host_addr, &self.peer_addr);
|
|
||||||
|
|
||||||
let _ = syscall::write(self.ip, &tcp.to_bytes());
|
|
||||||
let _ = syscall::close(self.ip);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A TCP resource
|
|
||||||
pub struct TcpResource {
|
|
||||||
pub stream: Arc<UnsafeCell<TcpStream>>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Resource for TcpResource {
|
|
||||||
fn dup(&self) -> Result<Box<TcpResource>> {
|
|
||||||
Ok(Box::new(TcpResource {
|
|
||||||
stream: self.stream.clone()
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn path(&self, buf: &mut [u8]) -> Result<usize> {
|
|
||||||
unsafe { (*self.stream.get()).path(buf) }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
|
|
||||||
unsafe { (*self.stream.get()).read(buf) }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write(&mut self, buf: &[u8]) -> Result<usize> {
|
|
||||||
unsafe { (*self.stream.get()).write(buf) }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sync(&mut self) -> Result<usize> {
|
|
||||||
unsafe { (*self.stream.get()).sync() }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,98 +0,0 @@
|
||||||
use std::cell::UnsafeCell;
|
|
||||||
use std::rand;
|
|
||||||
use std::sync::Arc;
|
|
||||||
use std::{str, u16};
|
|
||||||
|
|
||||||
use netutils::{getcfg, Ipv4Addr, Tcp, TCP_SYN, TCP_ACK};
|
|
||||||
use resource_scheme::ResourceScheme;
|
|
||||||
use syscall;
|
|
||||||
use syscall::error::{Error, Result, ENOENT, EINVAL};
|
|
||||||
use syscall::flag::O_RDWR;
|
|
||||||
|
|
||||||
use resource::{TcpResource, TcpStream};
|
|
||||||
|
|
||||||
/// A TCP scheme
|
|
||||||
pub struct TcpScheme;
|
|
||||||
|
|
||||||
impl ResourceScheme<TcpResource> for TcpScheme {
|
|
||||||
fn open_resource(&self, url: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result<Box<TcpResource>> {
|
|
||||||
let ip_addr = Ipv4Addr::from_str(&getcfg("ip").map_err(|err| err.into_sys())?);
|
|
||||||
|
|
||||||
let path = try!(str::from_utf8(url).or(Err(Error::new(EINVAL))));
|
|
||||||
let mut parts = path.split('/');
|
|
||||||
let remote = parts.next().unwrap_or("");
|
|
||||||
let path = parts.next().unwrap_or("");
|
|
||||||
|
|
||||||
let mut remote_parts = remote.split(':');
|
|
||||||
let host = remote_parts.next().unwrap_or("");
|
|
||||||
let port = remote_parts.next().unwrap_or("");
|
|
||||||
|
|
||||||
if ! host.is_empty() && ! port.is_empty() {
|
|
||||||
let peer_addr = Ipv4Addr::from_str(host);
|
|
||||||
let peer_port = port.parse::<u16>().unwrap_or(0);
|
|
||||||
let host_port = (rand() % 32768 + 32768) as u16;
|
|
||||||
|
|
||||||
match syscall::open(&format!("ip:{}/6", peer_addr.to_string()), O_RDWR) {
|
|
||||||
Ok(ip) => {
|
|
||||||
let mut stream = TcpStream {
|
|
||||||
ip: ip,
|
|
||||||
host_addr: ip_addr,
|
|
||||||
peer_addr: peer_addr,
|
|
||||||
peer_port: peer_port,
|
|
||||||
host_port: host_port,
|
|
||||||
sequence: rand() as u32,
|
|
||||||
acknowledge: 0,
|
|
||||||
finished: false
|
|
||||||
};
|
|
||||||
|
|
||||||
if stream.client_establish() {
|
|
||||||
return Ok(Box::new(TcpResource {
|
|
||||||
stream: Arc::new(UnsafeCell::new(stream))
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(err) => return Err(err),
|
|
||||||
}
|
|
||||||
} else if ! path.is_empty() {
|
|
||||||
let host_port = path.parse::<u16>().unwrap_or(0);
|
|
||||||
|
|
||||||
while let Ok(ip) = syscall::open("ip:/6", O_RDWR) {
|
|
||||||
let mut bytes = [0; 65536];
|
|
||||||
match syscall::read(ip, &mut bytes) {
|
|
||||||
Ok(count) => {
|
|
||||||
if let Some(segment) = Tcp::from_bytes(&bytes[..count]) {
|
|
||||||
if segment.header.dst.get() == host_port && segment.header.flags.get() & (TCP_SYN | TCP_ACK) == TCP_SYN {
|
|
||||||
let mut path = [0; 256];
|
|
||||||
if let Ok(path_count) = syscall::fpath(ip, &mut path) {
|
|
||||||
let ip_reference = unsafe { str::from_utf8_unchecked(&path[.. path_count]) }.split(':').nth(1).unwrap_or("");
|
|
||||||
let ip_remote = ip_reference.split('/').next().unwrap_or("");
|
|
||||||
let peer_addr = ip_remote.split(':').next().unwrap_or("");
|
|
||||||
|
|
||||||
let mut stream = TcpStream {
|
|
||||||
ip: ip,
|
|
||||||
host_addr: ip_addr,
|
|
||||||
peer_addr: Ipv4Addr::from_str(peer_addr),
|
|
||||||
peer_port: segment.header.src.get(),
|
|
||||||
host_port: host_port,
|
|
||||||
sequence: rand() as u32,
|
|
||||||
acknowledge: segment.header.sequence.get(),
|
|
||||||
finished: false
|
|
||||||
};
|
|
||||||
|
|
||||||
if stream.server_establish(segment) {
|
|
||||||
return Ok(Box::new(TcpResource {
|
|
||||||
stream: Arc::new(UnsafeCell::new(stream))
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(err) => return Err(err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Err(Error::new(ENOENT))
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -3,6 +3,7 @@ name = "udpd"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
event = { path = "../../crates/event/" }
|
||||||
netutils = { path = "../../programs/netutils/" }
|
netutils = { path = "../../programs/netutils/" }
|
||||||
resource_scheme = { path = "../../crates/resource_scheme/" }
|
rand = { git = "https://github.com/redox-os/rand.git" }
|
||||||
syscall = { path = "../../syscall/" }
|
syscall = { path = "../../syscall/" }
|
||||||
|
|
|
@ -1,30 +1,348 @@
|
||||||
#![feature(rand)]
|
extern crate event;
|
||||||
|
|
||||||
extern crate netutils;
|
extern crate netutils;
|
||||||
extern crate resource_scheme;
|
extern crate rand;
|
||||||
extern crate syscall;
|
extern crate syscall;
|
||||||
|
|
||||||
|
use rand::{Rng, OsRng};
|
||||||
|
use std::collections::{BTreeMap, VecDeque};
|
||||||
|
use std::cell::RefCell;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{Read, Write};
|
use std::io::{self, Read, Write};
|
||||||
use std::thread;
|
use std::{mem, slice, str, thread};
|
||||||
|
use std::os::unix::io::FromRawFd;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
use resource_scheme::ResourceScheme;
|
use event::EventQueue;
|
||||||
use syscall::Packet;
|
use netutils::{n16, Ipv4, Ipv4Addr, Ipv4Header, Udp, UdpHeader, Checksum};
|
||||||
|
use syscall::data::Packet;
|
||||||
|
use syscall::error::{Error, Result, EACCES, EADDRINUSE, EBADF, EINVAL, EMSGSIZE, ENOTCONN, EWOULDBLOCK};
|
||||||
|
use syscall::flag::{EVENT_READ, O_CREAT, O_RDWR, O_NONBLOCK};
|
||||||
|
use syscall::scheme::SchemeMut;
|
||||||
|
|
||||||
use scheme::UdpScheme;
|
fn parse_socket(socket: &str) -> (Ipv4Addr, u16) {
|
||||||
|
let mut socket_parts = socket.split(":");
|
||||||
|
let host = Ipv4Addr::from_str(socket_parts.next().unwrap_or(""));
|
||||||
|
let port = socket_parts.next().unwrap_or("").parse::<u16>().unwrap_or(0);
|
||||||
|
(host, port)
|
||||||
|
}
|
||||||
|
|
||||||
mod resource;
|
struct Handle {
|
||||||
mod scheme;
|
local: (Ipv4Addr, u16),
|
||||||
|
remote: (Ipv4Addr, u16),
|
||||||
|
flags: usize,
|
||||||
|
events: usize,
|
||||||
|
data: VecDeque<Vec<u8>>,
|
||||||
|
todo: VecDeque<Packet>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Udpd {
|
||||||
|
scheme_file: File,
|
||||||
|
udp_file: File,
|
||||||
|
ports: BTreeMap<u16, usize>,
|
||||||
|
next_id: usize,
|
||||||
|
handles: BTreeMap<usize, Handle>,
|
||||||
|
rng: OsRng,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Udpd {
|
||||||
|
fn new(scheme_file: File, udp_file: File) -> Self {
|
||||||
|
Udpd {
|
||||||
|
scheme_file: scheme_file,
|
||||||
|
udp_file: udp_file,
|
||||||
|
ports: BTreeMap::new(),
|
||||||
|
next_id: 1,
|
||||||
|
handles: BTreeMap::new(),
|
||||||
|
rng: OsRng::new().expect("udpd: failed to open RNG")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn scheme_event(&mut self) -> io::Result<()> {
|
||||||
|
loop {
|
||||||
|
let mut packet = Packet::default();
|
||||||
|
if self.scheme_file.read(&mut packet)? == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let a = packet.a;
|
||||||
|
self.handle(&mut packet);
|
||||||
|
if packet.a == (-EWOULDBLOCK) as usize {
|
||||||
|
packet.a = a;
|
||||||
|
if let Some(mut handle) = self.handles.get_mut(&packet.b) {
|
||||||
|
handle.todo.push_back(packet);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.scheme_file.write(&packet)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn udp_event(&mut self) -> io::Result<()> {
|
||||||
|
loop {
|
||||||
|
let mut bytes = [0; 65536];
|
||||||
|
let count = self.udp_file.read(&mut bytes)?;
|
||||||
|
if count == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if let Some(ip) = Ipv4::from_bytes(&bytes[.. count]) {
|
||||||
|
if let Some(udp) = Udp::from_bytes(&ip.data) {
|
||||||
|
for (id, handle) in self.handles.iter_mut() {
|
||||||
|
// Local address not set or IP dst matches or is broadcast
|
||||||
|
if (handle.local.0 == Ipv4Addr::NULL || ip.header.dst == handle.local.0 || ip.header.dst == Ipv4Addr::BROADCAST)
|
||||||
|
// Local port matches UDP dst
|
||||||
|
&& udp.header.dst.get() == handle.local.1
|
||||||
|
// Remote address not set or is broadcast, or IP src matches
|
||||||
|
&& (handle.remote.0 == Ipv4Addr::NULL || handle.remote.0 == Ipv4Addr::BROADCAST || ip.header.src == handle.remote.0)
|
||||||
|
// Remote port not set or UDP src matches
|
||||||
|
&& (handle.remote.1 == 0 || udp.header.src.get() == handle.remote.1)
|
||||||
|
{
|
||||||
|
handle.data.push_back(udp.data.clone());
|
||||||
|
|
||||||
|
while ! handle.todo.is_empty() && ! handle.data.is_empty() {
|
||||||
|
let mut packet = handle.todo.pop_front().unwrap();
|
||||||
|
let buf = unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) };
|
||||||
|
let data = handle.data.pop_front().unwrap();
|
||||||
|
|
||||||
|
let mut i = 0;
|
||||||
|
while i < buf.len() && i < data.len() {
|
||||||
|
buf[i] = data[i];
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
packet.a = i;
|
||||||
|
|
||||||
|
self.scheme_file.write(&packet)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if handle.events & EVENT_READ == EVENT_READ {
|
||||||
|
if let Some(data) = handle.data.get(0) {
|
||||||
|
self.scheme_file.write(&Packet {
|
||||||
|
id: 0,
|
||||||
|
pid: 0,
|
||||||
|
uid: 0,
|
||||||
|
gid: 0,
|
||||||
|
a: syscall::number::SYS_FEVENT,
|
||||||
|
b: *id,
|
||||||
|
c: EVENT_READ,
|
||||||
|
d: data.len()
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SchemeMut for Udpd {
|
||||||
|
fn open(&mut self, url: &[u8], flags: usize, uid: u32, _gid: u32) -> Result<usize> {
|
||||||
|
let path = str::from_utf8(url).or(Err(Error::new(EINVAL)))?;
|
||||||
|
|
||||||
|
let mut parts = path.split("/");
|
||||||
|
let remote = parse_socket(parts.next().unwrap_or(""));
|
||||||
|
let mut local = parse_socket(parts.next().unwrap_or(""));
|
||||||
|
|
||||||
|
if local.1 == 0 {
|
||||||
|
local.1 = self.rng.gen_range(32768, 65535);
|
||||||
|
}
|
||||||
|
|
||||||
|
if local.1 <= 1024 && uid != 0 {
|
||||||
|
return Err(Error::new(EACCES));
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.ports.contains_key(&local.1) {
|
||||||
|
return Err(Error::new(EADDRINUSE));
|
||||||
|
}
|
||||||
|
|
||||||
|
self.ports.insert(local.1, 1);
|
||||||
|
|
||||||
|
let id = self.next_id;
|
||||||
|
self.next_id += 1;
|
||||||
|
|
||||||
|
self.handles.insert(id, Handle {
|
||||||
|
local: local,
|
||||||
|
remote: remote,
|
||||||
|
flags: flags,
|
||||||
|
events: 0,
|
||||||
|
data: VecDeque::new(),
|
||||||
|
todo: VecDeque::new(),
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dup(&mut self, file: usize, buf: &[u8]) -> Result<usize> {
|
||||||
|
let mut handle = {
|
||||||
|
let handle = self.handles.get(&file).ok_or(Error::new(EBADF))?;
|
||||||
|
Handle {
|
||||||
|
local: handle.local,
|
||||||
|
remote: handle.remote,
|
||||||
|
flags: handle.flags,
|
||||||
|
events: 0,
|
||||||
|
data: handle.data.clone(),
|
||||||
|
todo: VecDeque::new(),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let path = str::from_utf8(buf).or(Err(Error::new(EINVAL)))?;
|
||||||
|
|
||||||
|
if handle.remote.0 == Ipv4Addr::NULL || handle.remote.1 == 0 {
|
||||||
|
handle.remote = parse_socket(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(mut port) = self.ports.get_mut(&handle.local.1) {
|
||||||
|
*port = *port + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let id = self.next_id;
|
||||||
|
self.next_id += 1;
|
||||||
|
|
||||||
|
self.handles.insert(id, handle);
|
||||||
|
|
||||||
|
Ok(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read(&mut self, file: usize, buf: &mut [u8]) -> Result<usize> {
|
||||||
|
let mut handle = self.handles.get_mut(&file).ok_or(Error::new(EBADF))?;
|
||||||
|
|
||||||
|
if handle.remote.0 == Ipv4Addr::NULL || handle.remote.1 == 0 {
|
||||||
|
Err(Error::new(ENOTCONN))
|
||||||
|
} else if let Some(data) = handle.data.pop_front() {
|
||||||
|
let mut i = 0;
|
||||||
|
while i < buf.len() && i < data.len() {
|
||||||
|
buf[i] = data[i];
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(i)
|
||||||
|
} else if handle.flags & O_NONBLOCK == O_NONBLOCK {
|
||||||
|
Ok(0)
|
||||||
|
} else {
|
||||||
|
Err(Error::new(EWOULDBLOCK))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(&mut self, file: usize, buf: &[u8]) -> Result<usize> {
|
||||||
|
let handle = self.handles.get(&file).ok_or(Error::new(EBADF))?;
|
||||||
|
|
||||||
|
if handle.remote.0 == Ipv4Addr::NULL || handle.remote.1 == 0 {
|
||||||
|
Err(Error::new(ENOTCONN))
|
||||||
|
} else if buf.len() >= 65507 {
|
||||||
|
Err(Error::new(EMSGSIZE))
|
||||||
|
} else {
|
||||||
|
let udp_data = buf.to_vec();
|
||||||
|
|
||||||
|
let udp = Udp {
|
||||||
|
header: UdpHeader {
|
||||||
|
src: n16::new(handle.local.1),
|
||||||
|
dst: n16::new(handle.remote.1),
|
||||||
|
len: n16::new((udp_data.len() + mem::size_of::<UdpHeader>()) as u16),
|
||||||
|
checksum: Checksum { data: 0 }
|
||||||
|
},
|
||||||
|
data: udp_data
|
||||||
|
};
|
||||||
|
|
||||||
|
let ip_data = udp.to_bytes();
|
||||||
|
|
||||||
|
let ip = Ipv4 {
|
||||||
|
header: Ipv4Header {
|
||||||
|
ver_hlen: 0x45,
|
||||||
|
services: 0,
|
||||||
|
len: n16::new((ip_data.len() + mem::size_of::<Ipv4Header>()) as u16),
|
||||||
|
id: n16::new(self.rng.gen()),
|
||||||
|
flags_fragment: n16::new(0),
|
||||||
|
ttl: 127,
|
||||||
|
proto: 0x11,
|
||||||
|
checksum: Checksum { data: 0 },
|
||||||
|
src: handle.local.0,
|
||||||
|
dst: handle.remote.0
|
||||||
|
},
|
||||||
|
options: Vec::new(),
|
||||||
|
data: ip_data
|
||||||
|
};
|
||||||
|
|
||||||
|
self.udp_file.write(&ip.to_bytes()).map_err(|err| err.into_sys()).and(Ok(buf.len()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fevent(&mut self, file: usize, flags: usize) -> Result<usize> {
|
||||||
|
let mut handle = self.handles.get_mut(&file).ok_or(Error::new(EBADF))?;
|
||||||
|
|
||||||
|
handle.events = flags;
|
||||||
|
|
||||||
|
Ok(file)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result<usize> {
|
||||||
|
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
|
||||||
|
|
||||||
|
let path_string = format!("udp:{}:{}/{}:{}", handle.remote.0.to_string(), handle.remote.1, handle.local.0.to_string(), handle.local.1);
|
||||||
|
let path = path_string.as_bytes();
|
||||||
|
|
||||||
|
let mut i = 0;
|
||||||
|
while i < buf.len() && i < path.len() {
|
||||||
|
buf[i] = path[i];
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fsync(&mut self, file: usize) -> Result<usize> {
|
||||||
|
let _handle = self.handles.get(&file).ok_or(Error::new(EBADF))?;
|
||||||
|
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn close(&mut self, file: usize) -> Result<usize> {
|
||||||
|
let handle = self.handles.remove(&file).ok_or(Error::new(EBADF))?;
|
||||||
|
|
||||||
|
let remove = if let Some(mut port) = self.ports.get_mut(&handle.local.1) {
|
||||||
|
*port = *port + 1;
|
||||||
|
*port == 0
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
|
if remove {
|
||||||
|
drop(self.ports.remove(&handle.local.1));
|
||||||
|
}
|
||||||
|
|
||||||
|
drop(handle);
|
||||||
|
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
let mut socket = File::create(":udp").expect("udpd: failed to create udp scheme");
|
let scheme_fd = syscall::open(":udp", O_RDWR | O_CREAT | O_NONBLOCK).expect("udpd: failed to create :udp");
|
||||||
let scheme = UdpScheme;
|
let scheme_file = unsafe { File::from_raw_fd(scheme_fd) };
|
||||||
loop {
|
|
||||||
let mut packet = Packet::default();
|
let udp_fd = syscall::open("ip:11", O_RDWR | O_NONBLOCK).expect("udpd: failed to open ip:11");
|
||||||
socket.read(&mut packet).expect("udpd: failed to read events from udp scheme");
|
let udp_file = unsafe { File::from_raw_fd(udp_fd) };
|
||||||
scheme.handle(&mut packet);
|
|
||||||
socket.write(&packet).expect("udpd: failed to write responses to udp scheme");
|
let udpd = Rc::new(RefCell::new(Udpd::new(scheme_file, udp_file)));
|
||||||
}
|
|
||||||
|
let mut event_queue = EventQueue::<()>::new().expect("udpd: failed to create event queue");
|
||||||
|
|
||||||
|
let udp_udpd = udpd.clone();
|
||||||
|
event_queue.add(udp_fd, move |_count: usize| -> io::Result<Option<()>> {
|
||||||
|
udp_udpd.borrow_mut().udp_event()?;
|
||||||
|
Ok(None)
|
||||||
|
}).expect("udpd: failed to listen to events on ip:11");
|
||||||
|
|
||||||
|
event_queue.add(scheme_fd, move |_count: usize| -> io::Result<Option<()>> {
|
||||||
|
udpd.borrow_mut().scheme_event()?;
|
||||||
|
Ok(None)
|
||||||
|
}).expect("udpd: failed to listen to events on :udp");
|
||||||
|
|
||||||
|
event_queue.trigger_all(0).expect("udpd: failed to trigger event queue");
|
||||||
|
|
||||||
|
event_queue.run().expect("udpd: failed to run event queue");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,115 +0,0 @@
|
||||||
use std::{cmp, mem};
|
|
||||||
|
|
||||||
use netutils::{n16, Ipv4Addr, Checksum, Udp, UdpHeader};
|
|
||||||
use resource_scheme::Resource;
|
|
||||||
use syscall;
|
|
||||||
use syscall::error::*;
|
|
||||||
|
|
||||||
/// UDP resource
|
|
||||||
pub struct UdpResource {
|
|
||||||
pub ip: usize,
|
|
||||||
pub data: Vec<u8>,
|
|
||||||
pub host_addr: Ipv4Addr,
|
|
||||||
pub peer_addr: Ipv4Addr,
|
|
||||||
pub peer_port: u16,
|
|
||||||
pub host_port: u16,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Resource for UdpResource {
|
|
||||||
fn dup(&self) -> Result<Box<UdpResource>> {
|
|
||||||
match syscall::dup(self.ip) {
|
|
||||||
Ok(ip) => {
|
|
||||||
Ok(Box::new(UdpResource {
|
|
||||||
ip: ip,
|
|
||||||
data: self.data.clone(),
|
|
||||||
host_addr: self.host_addr,
|
|
||||||
peer_addr: self.peer_addr,
|
|
||||||
peer_port: self.peer_port,
|
|
||||||
host_port: self.host_port,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
Err(err) => Err(err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn path(&self, buf: &mut [u8]) -> Result<usize> {
|
|
||||||
let path_string = format!("udp:{}:{}/{}", self.peer_addr.to_string(), self.peer_port, self.host_port);
|
|
||||||
let path = path_string.as_bytes();
|
|
||||||
|
|
||||||
for (b, p) in buf.iter_mut().zip(path.iter()) {
|
|
||||||
*b = *p;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(cmp::min(buf.len(), path.len()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
|
|
||||||
if ! self.data.is_empty() {
|
|
||||||
let mut bytes: Vec<u8> = Vec::new();
|
|
||||||
mem::swap(&mut self.data, &mut bytes);
|
|
||||||
|
|
||||||
// TODO: Allow splitting
|
|
||||||
let mut i = 0;
|
|
||||||
while i < buf.len() && i < bytes.len() {
|
|
||||||
buf[i] = bytes[i];
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Ok(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
loop {
|
|
||||||
let mut bytes = [0; 65536];
|
|
||||||
let count = try!(syscall::read(self.ip, &mut bytes));
|
|
||||||
|
|
||||||
if let Some(datagram) = Udp::from_bytes(&bytes[..count]) {
|
|
||||||
if datagram.header.dst.get() == self.host_port &&
|
|
||||||
datagram.header.src.get() == self.peer_port {
|
|
||||||
// TODO: Allow splitting
|
|
||||||
let mut i = 0;
|
|
||||||
while i < buf.len() && i < datagram.data.len() {
|
|
||||||
buf[i] = datagram.data[i];
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Ok(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write(&mut self, buf: &[u8]) -> Result<usize> {
|
|
||||||
let mut udp = Udp {
|
|
||||||
header: UdpHeader {
|
|
||||||
src: n16::new(self.host_port),
|
|
||||||
dst: n16::new(self.peer_port),
|
|
||||||
len: n16::new((mem::size_of::<UdpHeader>() + buf.len()) as u16),
|
|
||||||
checksum: Checksum { data: 0 },
|
|
||||||
},
|
|
||||||
data: Vec::from(buf),
|
|
||||||
};
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
let proto = n16::new(0x11);
|
|
||||||
let datagram_len = n16::new((mem::size_of::<UdpHeader>() + udp.data.len()) as u16);
|
|
||||||
udp.header.checksum.data =
|
|
||||||
Checksum::compile(Checksum::sum((&self.host_addr as *const Ipv4Addr) as usize,
|
|
||||||
mem::size_of::<Ipv4Addr>()) +
|
|
||||||
Checksum::sum((&self.peer_addr as *const Ipv4Addr) as usize,
|
|
||||||
mem::size_of::<Ipv4Addr>()) +
|
|
||||||
Checksum::sum((&proto as *const n16) as usize,
|
|
||||||
mem::size_of::<n16>()) +
|
|
||||||
Checksum::sum((&datagram_len as *const n16) as usize,
|
|
||||||
mem::size_of::<n16>()) +
|
|
||||||
Checksum::sum((&udp.header as *const UdpHeader) as usize,
|
|
||||||
mem::size_of::<UdpHeader>()) +
|
|
||||||
Checksum::sum(udp.data.as_ptr() as usize, udp.data.len()));
|
|
||||||
}
|
|
||||||
|
|
||||||
syscall::write(self.ip, &udp.to_bytes()).and(Ok(buf.len()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sync(&mut self) -> Result<usize> {
|
|
||||||
syscall::fsync(self.ip)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,73 +0,0 @@
|
||||||
use std::rand;
|
|
||||||
use std::{str, u16};
|
|
||||||
|
|
||||||
use netutils::{getcfg, Ipv4Addr, Udp};
|
|
||||||
use resource_scheme::ResourceScheme;
|
|
||||||
use syscall;
|
|
||||||
use syscall::error::{Error, Result, ENOENT, EINVAL};
|
|
||||||
use syscall::flag::O_RDWR;
|
|
||||||
|
|
||||||
use resource::UdpResource;
|
|
||||||
|
|
||||||
/// UDP UdpScheme
|
|
||||||
pub struct UdpScheme;
|
|
||||||
|
|
||||||
impl ResourceScheme<UdpResource> for UdpScheme {
|
|
||||||
fn open_resource(&self, url: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result<Box<UdpResource>> {
|
|
||||||
let ip_addr = Ipv4Addr::from_str(&getcfg("ip").map_err(|err| err.into_sys())?);
|
|
||||||
|
|
||||||
let path = try!(str::from_utf8(url).or(Err(Error::new(EINVAL))));
|
|
||||||
let mut parts = path.split('/');
|
|
||||||
let remote = parts.next().unwrap_or("");
|
|
||||||
let path = parts.next().unwrap_or("");
|
|
||||||
|
|
||||||
// Check host and port vs path
|
|
||||||
if remote.is_empty() {
|
|
||||||
let host_port = path.parse::<u16>().unwrap_or(0);
|
|
||||||
if host_port > 0 {
|
|
||||||
while let Ok(ip) = syscall::open("ip:/11", O_RDWR) {
|
|
||||||
let mut bytes = [0; 65536];
|
|
||||||
if let Ok(count) = syscall::read(ip, &mut bytes) {
|
|
||||||
if let Some(datagram) = Udp::from_bytes(&bytes[..count]) {
|
|
||||||
if datagram.header.dst.get() == host_port {
|
|
||||||
let mut path = [0; 256];
|
|
||||||
if let Ok(path_count) = syscall::fpath(ip, &mut path) {
|
|
||||||
let ip_reference = unsafe { str::from_utf8_unchecked(&path[.. path_count]) }.split(':').nth(1).unwrap_or("");
|
|
||||||
let peer_addr = ip_reference.split('/').next().unwrap_or("").split(':').next().unwrap_or("");
|
|
||||||
|
|
||||||
return Ok(Box::new(UdpResource {
|
|
||||||
ip: ip,
|
|
||||||
data: datagram.data,
|
|
||||||
host_addr: ip_addr,
|
|
||||||
peer_addr: Ipv4Addr::from_str(peer_addr),
|
|
||||||
peer_port: datagram.header.src.get(),
|
|
||||||
host_port: host_port,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let mut remote_parts = remote.split(':');
|
|
||||||
let peer_addr = remote_parts.next().unwrap_or("");
|
|
||||||
let peer_port = remote_parts.next().unwrap_or("").parse::<u16>().unwrap_or(0);
|
|
||||||
if peer_port > 0 {
|
|
||||||
let host_port = path.parse::<u16>().unwrap_or((rand() % 32768 + 32768) as u16);
|
|
||||||
if let Ok(ip) = syscall::open(&format!("ip:{}/11", peer_addr), O_RDWR) {
|
|
||||||
return Ok(Box::new(UdpResource {
|
|
||||||
ip: ip,
|
|
||||||
data: Vec::new(),
|
|
||||||
host_addr: ip_addr,
|
|
||||||
peer_addr: Ipv4Addr::from_str(peer_addr),
|
|
||||||
peer_port: peer_port as u16,
|
|
||||||
host_port: host_port,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Err(Error::new(ENOENT))
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -48,8 +48,8 @@ pub fn clock_gettime(clock: usize, tp: &mut TimeSpec) -> Result<usize> {
|
||||||
unsafe { syscall2(SYS_CLOCK_GETTIME, clock, tp as *mut TimeSpec as usize) }
|
unsafe { syscall2(SYS_CLOCK_GETTIME, clock, tp as *mut TimeSpec as usize) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dup(fd: usize) -> Result<usize> {
|
pub fn dup(fd: usize, buf: &[u8]) -> Result<usize> {
|
||||||
unsafe { syscall1(SYS_DUP, fd) }
|
unsafe { syscall3(SYS_DUP, fd, buf.as_ptr() as usize, buf.len()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn execve(path: &str, args: &[[usize; 2]]) -> Result<usize> {
|
pub fn execve(path: &str, args: &[[usize; 2]]) -> Result<usize> {
|
||||||
|
|
|
@ -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_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_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_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_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),
|
SYS_LSEEK => self.seek(packet.b, packet.c, packet.d),
|
||||||
|
@ -49,7 +49,7 @@ pub trait Scheme {
|
||||||
|
|
||||||
/* Resource operations */
|
/* Resource operations */
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn dup(&self, old_id: usize) -> Result<usize> {
|
fn dup(&self, old_id: usize, buf: &[u8]) -> Result<usize> {
|
||||||
Err(Error::new(EBADF))
|
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_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_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_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_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),
|
SYS_LSEEK => self.seek(packet.b, packet.c, packet.d),
|
||||||
|
@ -145,7 +145,7 @@ pub trait SchemeMut {
|
||||||
|
|
||||||
/* Resource operations */
|
/* Resource operations */
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn dup(&mut self, old_id: usize) -> Result<usize> {
|
fn dup(&mut self, old_id: usize, buf: &[u8]) -> Result<usize> {
|
||||||
Err(Error::new(EBADF))
|
Err(Error::new(EBADF))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue