From daaa8a3a396b128a6b15511155703d9c0d7368b1 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 9 May 2017 21:31:09 -0600 Subject: [PATCH] Add ethernetd, ipd, tcpd, and udpd --- Cargo.toml | 21 + src/ethernetd/main.rs | 110 ++++ src/ethernetd/scheme.rs | 164 ++++++ src/ipd/interface/ethernet.rs | 155 ++++++ src/ipd/interface/loopback.rs | 50 ++ src/ipd/interface/mod.rs | 19 + src/ipd/main.rs | 341 +++++++++++++ src/tcpd/main.rs | 937 ++++++++++++++++++++++++++++++++++ src/udpd/main.rs | 586 +++++++++++++++++++++ 9 files changed, 2383 insertions(+) create mode 100644 Cargo.toml create mode 100644 src/ethernetd/main.rs create mode 100644 src/ethernetd/scheme.rs create mode 100644 src/ipd/interface/ethernet.rs create mode 100644 src/ipd/interface/loopback.rs create mode 100644 src/ipd/interface/mod.rs create mode 100644 src/ipd/main.rs create mode 100644 src/tcpd/main.rs create mode 100644 src/udpd/main.rs diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000000..393ef6e3e1 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "redox_netstack" +version = "0.1.0" + +[[bin]] +name = "ipd" +path = "src/ipd/main.rs" + +[[bin]] +name = "tcpd" +path = "src/tcpd/main.rs" + +[[bin]] +name = "udpd" +path = "src/udpd/main.rs" + +[dependencies] +netutils = { git = "https://github.com/redox-os/netutils.git" } +rand = "0.3" +redox_event = "0.1" +redox_syscall = "0.1" diff --git a/src/ethernetd/main.rs b/src/ethernetd/main.rs new file mode 100644 index 0000000000..7185435937 --- /dev/null +++ b/src/ethernetd/main.rs @@ -0,0 +1,110 @@ +extern crate event; +extern crate netutils; +extern crate syscall; + +use event::EventQueue; +use std::cell::RefCell; +use std::fs::File; +use std::io::{Result, Read, Write}; +use std::os::unix::io::FromRawFd; +use std::process; +use std::rc::Rc; + +use syscall::{Packet, SchemeMut, EWOULDBLOCK}; + +use scheme::EthernetScheme; + +mod scheme; + +fn daemon(network_fd: usize, socket_fd: usize) { + let network = unsafe { File::from_raw_fd(network_fd) }; + let socket = Rc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd) })); + let scheme = Rc::new(RefCell::new(EthernetScheme::new(network))); + let todo = Rc::new(RefCell::new(Vec::::new())); + + let mut event_queue = EventQueue::<()>::new().expect("ethernetd: failed to create event queue"); + + let socket_net = socket.clone(); + let scheme_net = scheme.clone(); + let todo_net = todo.clone(); + event_queue.add(network_fd, move |_count: usize| -> Result> { + if scheme_net.borrow_mut().input()? > 0 { + let mut todo = todo_net.borrow_mut(); + let mut i = 0; + while i < todo.len() { + let a = todo[i].a; + scheme_net.borrow_mut().handle(&mut todo[i]); + if todo[i].a == (-EWOULDBLOCK) as usize { + todo[i].a = a; + i += 1; + } else { + socket_net.borrow_mut().write(&mut todo[i])?; + todo.remove(i); + } + } + + for (id, handle) in scheme_net.borrow_mut().handles.iter() { + if let Some(frame) = handle.frames.get(0) { + socket_net.borrow_mut().write(&Packet { + id: 0, + pid: 0, + uid: 0, + gid: 0, + a: syscall::number::SYS_FEVENT, + b: *id, + c: syscall::flag::EVENT_READ, + d: frame.data.len() + })?; + } + } + } + Ok(None) + }).expect("ethernetd: failed to listen for network events"); + + event_queue.add(socket_fd, move |_count: usize| -> Result> { + loop { + let mut packet = Packet::default(); + if socket.borrow_mut().read(&mut packet)? == 0 { + break; + } + + let a = packet.a; + scheme.borrow_mut().handle(&mut packet); + if packet.a == (-EWOULDBLOCK) as usize { + packet.a = a; + todo.borrow_mut().push(packet); + } else { + socket.borrow_mut().write(&mut packet)?; + } + } + + Ok(None) + }).expect("ethernetd: failed to listen for scheme events"); + + event_queue.trigger_all(0).expect("ethernetd: failed to trigger events"); + + event_queue.run().expect("ethernetd: failed to run event loop"); +} + +fn main() { + match syscall::open("network:", syscall::O_RDWR | syscall::O_NONBLOCK) { + Ok(network_fd) => { + // Daemonize + if unsafe { syscall::clone(0).unwrap() } == 0 { + match syscall::open(":ethernet", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK) { + Ok(socket_fd) => { + daemon(network_fd, socket_fd); + }, + Err(err) => { + println!("ethernetd: failed to create ethernet scheme: {}", err); + process::exit(1); + } + } + } + }, + Err(err) => { + println!("ethernetd: failed to open network: {}", err); + process::exit(1); + } + } +} diff --git a/src/ethernetd/scheme.rs b/src/ethernetd/scheme.rs new file mode 100644 index 0000000000..7b1b3bdda9 --- /dev/null +++ b/src/ethernetd/scheme.rs @@ -0,0 +1,164 @@ +use std::collections::{BTreeMap, VecDeque}; +use std::fs::File; +use std::io::{self, Read, Write}; +use std::os::unix::io::AsRawFd; +use std::{cmp, str, u16}; + +use netutils::{getcfg, MacAddr, EthernetII}; +use syscall; +use syscall::error::{Error, Result, EACCES, EBADF, EINVAL, EIO, EWOULDBLOCK}; +use syscall::flag::O_NONBLOCK; +use syscall::scheme::SchemeMut; + +#[derive(Clone)] +pub struct Handle { + /// The flags this handle was opened with + flags: usize, + /// The Host's MAC address + pub host_addr: MacAddr, + /// The ethernet type + pub ethertype: u16, + /// The data + pub frames: VecDeque, +} + +pub struct EthernetScheme { + network: File, + next_id: usize, + pub handles: BTreeMap +} + +impl EthernetScheme { + pub fn new(network: File) -> EthernetScheme { + EthernetScheme { + network: network, + next_id: 1, + handles: BTreeMap::new(), + } + } + + //TODO: Minimize allocation + //TODO: Reduce iteration cost (use BTreeMap of ethertype to handle?) + pub fn input(&mut self) -> io::Result { + let mut total = 0; + loop { + let mut bytes = [0; 65536]; + let count = self.network.read(&mut bytes)?; + if count == 0 { + break; + } + if let Some(frame) = EthernetII::from_bytes(&bytes[.. count]) { + for (_id, handle) in self.handles.iter_mut() { + if frame.header.ethertype.get() == handle.ethertype { + handle.frames.push_back(frame.clone()); + } + } + total += count; + } + } + Ok(total) + } +} + +impl SchemeMut for EthernetScheme { + fn open(&mut self, url: &[u8], flags: usize, uid: u32, _gid: u32) -> Result { + if uid == 0 { + let mac_addr = MacAddr::from_str(&getcfg("mac").map_err(|err| Error::new(err.raw_os_error().unwrap_or(EIO)))?); + let path = try!(str::from_utf8(url).or(Err(Error::new(EINVAL)))); + + let ethertype = u16::from_str_radix(path, 16).unwrap_or(0); + + let next_id = self.next_id; + self.next_id += 1; + + self.handles.insert(next_id, Handle { + flags: flags, + host_addr: mac_addr, + ethertype: ethertype, + frames: VecDeque::new() + }); + + Ok(next_id) + } else { + Err(Error::new(EACCES)) + } + } + + fn dup(&mut self, id: usize, _buf: &[u8]) -> Result { + let next_id = self.next_id; + self.next_id += 1; + + let handle = { + let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + handle.clone() + }; + + self.handles.insert(next_id, handle); + + Ok(next_id) + } + + fn read(&mut self, id: usize, buf: &mut [u8]) -> Result { + let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?; + + if let Some(frame) = handle.frames.pop_front() { + let data = frame.to_bytes(); + for (b, d) in buf.iter_mut().zip(data.iter()) { + *b = *d; + } + + Ok(cmp::min(buf.len(), data.len())) + } else if handle.flags & O_NONBLOCK == O_NONBLOCK { + Ok(0) + } else { + Err(Error::new(EWOULDBLOCK)) + } + } + + fn write(&mut self, id: usize, buf: &[u8]) -> Result { + let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + + if let Some(mut frame) = EthernetII::from_bytes(buf) { + frame.header.src = handle.host_addr; + frame.header.ethertype.set(handle.ethertype); + self.network.write(&frame.to_bytes()).map_err(|err| Error::new(err.raw_os_error().unwrap_or(EIO))) + } else { + Err(Error::new(EINVAL)) + } + } + + fn fevent(&mut self, id: usize, _flags: usize) -> Result { + let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + + Ok(id) + } + + fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result { + let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + + let path_string = format!("ethernet:{:X}", handle.ethertype); + 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, id: usize) -> Result { + let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + + syscall::fsync(self.network.as_raw_fd()) + } + + fn close(&mut self, id: usize) -> Result { + let handle = self.handles.remove(&id).ok_or(Error::new(EBADF))?; + + drop(handle); + + Ok(0) + } +} diff --git a/src/ipd/interface/ethernet.rs b/src/ipd/interface/ethernet.rs new file mode 100644 index 0000000000..d914a78431 --- /dev/null +++ b/src/ipd/interface/ethernet.rs @@ -0,0 +1,155 @@ +use netutils::{getcfg, n16, Ipv4Addr, MacAddr, Ipv4, EthernetII, EthernetIIHeader, Arp}; +use std::collections::BTreeMap; +use std::fs::File; +use std::io::{Result, Read, Write}; +use std::os::unix::io::FromRawFd; + +use interface::Interface; + +pub struct EthernetInterface { + mac: MacAddr, + ip: Ipv4Addr, + router: Ipv4Addr, + subnet: Ipv4Addr, + arp_file: File, + ip_file: File, + arp: BTreeMap, + rarp: BTreeMap, +} + +impl EthernetInterface { + pub fn new(arp_fd: usize, ip_fd: usize) -> Self { + EthernetInterface { + 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(), + } + } +} + +impl Interface for EthernetInterface { + fn ip(&self) -> Ipv4Addr { + self.ip + } + + fn routable(&self, dst: Ipv4Addr) -> bool { + dst != Ipv4Addr::LOOPBACK + } + + fn arp_event(&mut self) -> Result<()> { + loop { + let mut bytes = [0; 65536]; + let count = self.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 == self.ip { + if packet.header.src_ip != Ipv4Addr::BROADCAST && frame.header.src != MacAddr::BROADCAST { + self.arp.insert(packet.header.src_ip, frame.header.src); + self.rarp.insert(frame.header.src, packet.header.src_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 = self.mac; + response.header.src_ip = self.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 = self.mac; + + self.arp_file.write(&response_frame.to_bytes())?; + } + } + } + } + } + + Ok(()) + } + + fn recv(&mut self) -> Result> { + let mut ips = Vec::new(); + + loop { + let mut bytes = [0; 65536]; + let count = self.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 == self.ip || ip.header.dst == Ipv4Addr::BROADCAST { + //TODO: Handle ping here + + if ip.header.src != Ipv4Addr::BROADCAST && frame.header.src != MacAddr::BROADCAST { + self.arp.insert(ip.header.src, frame.header.src); + self.rarp.insert(frame.header.src, ip.header.src); + } + + ips.push(ip); + } + } + } + } + + Ok(ips) + } + + fn send(&mut self, ip: Ipv4) -> Result { + let mut dst = MacAddr::BROADCAST; + if ip.header.dst != Ipv4Addr::BROADCAST { + let mut needs_routing = false; + + for octet in 0..4 { + let me = self.ip.bytes[octet]; + let mask = self.subnet.bytes[octet]; + let them = ip.header.dst.bytes[octet]; + if me & mask != them & mask { + needs_routing = true; + break; + } + } + + let route_addr = if needs_routing { + self.router + } else { + ip.header.dst + }; + + if let Some(mac) = self.arp.get(&route_addr) { + dst = *mac; + } else { + println!("ipd: need to arp {}", route_addr.to_string()); + } + } + + let frame = EthernetII { + header: EthernetIIHeader { + dst: dst, + src: self.mac, + ethertype: n16::new(0x800), + }, + data: ip.to_bytes() + }; + + self.ip_file.write(&frame.to_bytes()) + } +} diff --git a/src/ipd/interface/loopback.rs b/src/ipd/interface/loopback.rs new file mode 100644 index 0000000000..a957ef8818 --- /dev/null +++ b/src/ipd/interface/loopback.rs @@ -0,0 +1,50 @@ +use netutils::{Ipv4Addr, Ipv4}; +use std::io::Result; + +use interface::Interface; + +pub struct LoopbackInterface { + packets: Vec +} + +impl LoopbackInterface { + pub fn new() -> Self { + LoopbackInterface { + packets: Vec::new() + } + } +} + +impl Interface for LoopbackInterface { + fn ip(&self) -> Ipv4Addr { + Ipv4Addr::LOOPBACK + } + + fn routable(&self, dst: Ipv4Addr) -> bool { + dst == Ipv4Addr::LOOPBACK + } + + fn recv(&mut self) -> Result> { + let mut ips = Vec::new(); + + for ip in self.packets.drain(..) { + ips.push(ip); + } + + Ok(ips) + } + + fn send(&mut self, ip: Ipv4) -> Result { + self.packets.push(ip); + + Ok(0) + } + + fn arp_event(&mut self) -> Result<()> { + Ok(()) + } + + fn has_loopback_data(&self) -> bool { + ! self.packets.is_empty() + } +} diff --git a/src/ipd/interface/mod.rs b/src/ipd/interface/mod.rs new file mode 100644 index 0000000000..2fa89d9d2e --- /dev/null +++ b/src/ipd/interface/mod.rs @@ -0,0 +1,19 @@ +use netutils::{Ipv4, Ipv4Addr}; +use std::io::Result; + +pub use self::ethernet::EthernetInterface; +pub use self::loopback::LoopbackInterface; + +mod ethernet; +mod loopback; + +pub trait Interface { + fn ip(&self) -> Ipv4Addr; + fn routable(&self, dst: Ipv4Addr) -> bool; + fn recv(&mut self) -> Result>; + fn send(&mut self, ip: Ipv4) -> Result; + + fn arp_event(&mut self) -> Result<()>; + + fn has_loopback_data(&self) -> bool { false } +} diff --git a/src/ipd/main.rs b/src/ipd/main.rs new file mode 100644 index 0000000000..49e332fcf7 --- /dev/null +++ b/src/ipd/main.rs @@ -0,0 +1,341 @@ +extern crate event; +extern crate netutils; +extern crate syscall; + +use event::EventQueue; +use netutils::{Ipv4Addr, Ipv4, Tcp}; +use std::cell::RefCell; +use std::collections::{BTreeMap, VecDeque}; +use std::fs::File; +use std::io::{self, Read, Write}; +use std::os::unix::io::FromRawFd; +use std::{process, slice, str}; +use std::rc::Rc; +use syscall::data::Packet; +use syscall::error::{Error, Result, EACCES, EADDRNOTAVAIL, EBADF, EIO, EINVAL, ENOENT, EWOULDBLOCK}; +use syscall::flag::{EVENT_READ, O_NONBLOCK}; +use syscall::scheme::SchemeMut; + +use interface::{Interface, EthernetInterface, LoopbackInterface}; + +mod interface; + +struct Handle { + proto: u8, + flags: usize, + events: usize, + data: VecDeque>, + todo: VecDeque, +} + +struct Ipd { + scheme_file: File, + interfaces: Vec>, + next_id: usize, + handles: BTreeMap, +} + +impl Ipd { + fn new(scheme_file: File) -> Self { + Ipd { + scheme_file: scheme_file, + interfaces: Vec::new(), + next_id: 1, + handles: BTreeMap::new(), + } + } + + fn scheme_event(&mut self) -> io::Result<()> { + loop { + let mut packet = Packet::default(); + if self.scheme_file.read(&mut packet)? == 0 { + break; + } + + let a = packet.a; + self.handle(&mut packet); + if packet.a == (-EWOULDBLOCK) as usize { + packet.a = a; + if let Some(mut handle) = self.handles.get_mut(&packet.b) { + handle.todo.push_back(packet); + } + } else { + self.scheme_file.write(&packet)?; + } + } + + Ok(()) + } + + fn ip_event(&mut self, if_id: usize) -> io::Result<()> { + if let Some(mut interface) = self.interfaces.get_mut(if_id) { + for ip in interface.recv()? { + for (id, handle) in self.handles.iter_mut() { + if ip.header.proto == handle.proto { + handle.data.push_back(ip.to_bytes()); + + 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(()) + } + + fn loopback_event(&mut self, loopback_id: usize) -> io::Result<()> { + let handle_loopback = if let Some(interface) = self.interfaces.get(loopback_id) { + interface.has_loopback_data() + } else { + false + }; + + if handle_loopback { + self.ip_event(loopback_id)?; + } + + Ok(()) + } +} + +impl SchemeMut for Ipd { + fn open(&mut self, url: &[u8], flags: usize, uid: u32, _gid: u32) -> Result { + if uid == 0 { + let path = str::from_utf8(url).or(Err(Error::new(EINVAL)))?; + + let proto = u8::from_str_radix(path, 16).or(Err(Error::new(ENOENT)))?; + + let id = self.next_id; + self.next_id += 1; + + self.handles.insert(id, Handle { + proto: proto, + flags: flags, + events: 0, + data: VecDeque::new(), + todo: VecDeque::new(), + }); + + Ok(id) + } else { + Err(Error::new(EACCES)) + } + } + + fn dup(&mut self, file: usize, _buf: &[u8]) -> Result { + let handle = { + let handle = self.handles.get(&file).ok_or(Error::new(EBADF))?; + Handle { + proto: handle.proto, + flags: handle.flags, + events: 0, + data: handle.data.clone(), + todo: VecDeque::new(), + } + }; + + let id = self.next_id; + self.next_id += 1; + + self.handles.insert(id, handle); + + Ok(id) + } + + fn read(&mut self, file: usize, buf: &mut [u8]) -> Result { + let mut handle = self.handles.get_mut(&file).ok_or(Error::new(EBADF))?; + + if let Some(data) = handle.data.pop_front() { + let mut i = 0; + while i < buf.len() && i < data.len() { + buf[i] = data[i]; + i += 1; + } + + Ok(i) + } else if handle.flags & O_NONBLOCK == O_NONBLOCK { + Ok(0) + } else { + Err(Error::new(EWOULDBLOCK)) + } + } + + fn write(&mut self, file: usize, buf: &[u8]) -> Result { + let handle = self.handles.get(&file).ok_or(Error::new(EBADF))?; + + if let Some(mut ip) = Ipv4::from_bytes(buf) { + for mut interface in self.interfaces.iter_mut() { + let if_ip = interface.ip(); + if ip.header.src == if_ip || (ip.header.src == Ipv4Addr::NULL && interface.routable(ip.header.dst)) { + ip.header.src = if_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(); + + interface.send(ip).map_err(|err| Error::new(err.raw_os_error().unwrap_or(EIO)))?; + + return Ok(buf.len()); + } + } + + Err(Error::new(EADDRNOTAVAIL)) + } else { + Err(Error::new(EINVAL)) + } + } + + fn fevent(&mut self, file: usize, flags: usize) -> Result { + let mut handle = self.handles.get_mut(&file).ok_or(Error::new(EBADF))?; + + handle.events = flags; + + Ok(file) + } + + fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result { + let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + + let path_string = format!("ip:{:X}", handle.proto); + let path = path_string.as_bytes(); + + let mut i = 0; + while i < buf.len() && i < path.len() { + buf[i] = path[i]; + i += 1; + } + + Ok(i) + } + + fn fsync(&mut self, file: usize) -> Result { + let _handle = self.handles.get(&file).ok_or(Error::new(EBADF))?; + + Ok(0) + } + + fn close(&mut self, file: usize) -> Result { + let handle = self.handles.remove(&file).ok_or(Error::new(EBADF))?; + + drop(handle); + + Ok(0) + } +} + +fn daemon(arp_fd: usize, ip_fd: usize, scheme_fd: usize) { + let scheme_file = unsafe { File::from_raw_fd(scheme_fd) }; + + let ipd = Rc::new(RefCell::new(Ipd::new(scheme_file))); + + let mut event_queue = EventQueue::<()>::new().expect("ipd: failed to create event queue"); + + //TODO: Multiple interfaces + { + let if_id = { + let mut ipd = ipd.borrow_mut(); + let if_id = ipd.interfaces.len(); + ipd.interfaces.push(Box::new(EthernetInterface::new(arp_fd, ip_fd))); + if_id + }; + + let arp_ipd = ipd.clone(); + event_queue.add(arp_fd, move |_count: usize| -> io::Result> { + if let Some(mut interface) = arp_ipd.borrow_mut().interfaces.get_mut(if_id) { + interface.arp_event()?; + } + + Ok(None) + }).expect("ipd: failed to listen to events on ethernet:806"); + + let ip_ipd = ipd.clone(); + event_queue.add(ip_fd, move |_count: usize| -> io::Result> { + ip_ipd.borrow_mut().ip_event(if_id)?; + + Ok(None) + }).expect("ipd: failed to listen to events on ethernet:800"); + } + + let loopback_id = { + let mut ipd = ipd.borrow_mut(); + let if_id = ipd.interfaces.len(); + ipd.interfaces.push(Box::new(LoopbackInterface::new())); + if_id + }; + + event_queue.add(scheme_fd, move |_count: usize| -> io::Result> { + let mut ipd = ipd.borrow_mut(); + + ipd.loopback_event(loopback_id)?; + ipd.scheme_event()?; + ipd.loopback_event(loopback_id)?; + + 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"); +} + +fn main() { + match syscall::open("ethernet:806", syscall::O_RDWR | syscall::O_NONBLOCK) { + Ok(arp_fd) => match syscall::open("ethernet:800", syscall::O_RDWR | syscall::O_NONBLOCK) { + Ok(ip_fd) => { + // Daemonize + if unsafe { syscall::clone(0).unwrap() } == 0 { + match syscall::open(":ip", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK) { + Ok(scheme_fd) => { + daemon(arp_fd, ip_fd, scheme_fd); + }, + Err(err) => { + println!("ipd: failed to create ip scheme: {}", err); + process::exit(1); + } + } + } + }, + Err(err) => { + println!("ipd: failed to open ethernet:800: {}", err); + process::exit(1); + } + }, + Err(err) => { + println!("ipd: failed to open ethernet:806: {}", err); + process::exit(1); + } + } +} diff --git a/src/tcpd/main.rs b/src/tcpd/main.rs new file mode 100644 index 0000000000..8878b006f3 --- /dev/null +++ b/src/tcpd/main.rs @@ -0,0 +1,937 @@ +extern crate event; +extern crate netutils; +extern crate rand; +extern crate syscall; + +use rand::{Rng, OsRng}; +use std::collections::{BTreeMap, VecDeque}; +use std::cell::RefCell; +use std::fs::File; +use std::io::{self, Read, Write}; +use std::{mem, process, slice, str}; +use std::ops::{Deref, DerefMut}; +use std::os::unix::io::FromRawFd; +use std::rc::Rc; + +use event::EventQueue; +use netutils::{n16, n32, Ipv4, Ipv4Addr, Ipv4Header, Tcp, TcpHeader, Checksum, TCP_FIN, TCP_SYN, TCP_RST, TCP_PSH, TCP_ACK}; +use syscall::data::{Packet, TimeSpec}; +use syscall::error::{Error, Result, EACCES, EADDRINUSE, EBADF, EIO, EINVAL, EISCONN, EMSGSIZE, ENOTCONN, ETIMEDOUT, EWOULDBLOCK}; +use syscall::flag::{CLOCK_MONOTONIC, EVENT_READ, F_GETFL, F_SETFL, O_ACCMODE, O_CREAT, O_RDWR, O_NONBLOCK}; +use syscall::scheme::SchemeMut; + +fn add_time(a: &TimeSpec, b: &TimeSpec) -> TimeSpec { + let mut secs = a.tv_sec + b.tv_sec; + + let mut nsecs = a.tv_nsec + b.tv_nsec; + while nsecs >= 1000000000 { + nsecs -= 1000000000; + secs += 1; + } + + TimeSpec { + tv_sec: secs, + tv_nsec: nsecs + } +} + +fn parse_socket(socket: &str) -> (Ipv4Addr, u16) { + let mut socket_parts = socket.split(":"); + let host = Ipv4Addr::from_str(socket_parts.next().unwrap_or("")); + let port = socket_parts.next().unwrap_or("").parse::().unwrap_or(0); + (host, port) +} + +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +enum State { + Listen, + SynSent, + SynReceived, + Established, + FinWait1, + FinWait2, + CloseWait, + Closing, + LastAck, + TimeWait, + Closed +} + +struct TcpHandle { + local: (Ipv4Addr, u16), + remote: (Ipv4Addr, u16), + flags: usize, + events: usize, + read_timeout: Option, + write_timeout: Option, + ttl: u8, + state: State, + seq: u32, + ack: u32, + data: VecDeque<(Ipv4, Tcp)>, + todo_dup: VecDeque, + todo_read: VecDeque<(Option, Packet)>, + todo_write: VecDeque<(Option, Packet)>, +} + +impl TcpHandle { + fn is_connected(&self) -> bool { + self.remote.0 != Ipv4Addr::NULL && self.remote.1 != 0 + } + + fn read_closed(&self) -> bool { + self.state == State::CloseWait || self.state == State::LastAck || self.state == State::TimeWait || self.state == State::Closed + } + + fn matches(&self, ip: &Ipv4, tcp: &Tcp) -> bool { + // Local address not set or IP dst matches or is broadcast + (self.local.0 == Ipv4Addr::NULL || ip.header.dst == self.local.0 || ip.header.dst == Ipv4Addr::BROADCAST) + // Local port matches UDP dst + && tcp.header.dst.get() == self.local.1 + // Remote address not set or is broadcast, or IP src matches + && (self.remote.0 == Ipv4Addr::NULL || self.remote.0 == Ipv4Addr::BROADCAST || ip.header.src == self.remote.0) + // Remote port not set or UDP src matches + && (self.remote.1 == 0 || tcp.header.src.get() == self.remote.1) + } + + fn create_tcp(&self, flags: u16, data: Vec) -> Tcp { + Tcp { + header: TcpHeader { + src: n16::new(self.local.1), + dst: n16::new(self.remote.1), + sequence: n32::new(self.seq), + ack_num: n32::new(self.ack), + flags: n16::new(((mem::size_of::() << 10) & 0xF000) as u16 | (flags & 0xFFF)), + window_size: n16::new(8192), + checksum: Checksum { data: 0 }, + urgent_pointer: n16::new(0), + }, + options: Vec::new(), + data: data + } + } + + fn create_ip(&self, id: u16, data: Vec) -> Ipv4 { + Ipv4 { + header: Ipv4Header { + ver_hlen: 0x45, + services: 0, + len: n16::new((data.len() + mem::size_of::()) as u16), + id: n16::new(id), + flags_fragment: n16::new(0), + ttl: self.ttl, + proto: 0x06, + checksum: Checksum { data: 0 }, + src: self.local.0, + dst: self.remote.0 + }, + options: Vec::new(), + data: data + } + } +} + +#[derive(Copy, Clone)] +enum SettingKind { + Ttl, + ReadTimeout, + WriteTimeout +} + +enum Handle { + Tcp(TcpHandle), + Setting(usize, SettingKind), +} + +struct Tcpd { + scheme_file: File, + tcp_file: File, + time_file: File, + ports: BTreeMap, + next_id: usize, + handles: BTreeMap, + rng: OsRng, +} + +impl Tcpd { + fn new(scheme_file: File, tcp_file: File, time_file: File) -> Self { + Tcpd { + scheme_file: scheme_file, + tcp_file: tcp_file, + time_file: time_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) { + if let Handle::Tcp(ref mut handle) = *handle { + match a { + syscall::number::SYS_DUP => { + packet.a = a; + handle.todo_dup.push_back(packet); + }, + syscall::number::SYS_READ => { + packet.a = a; + + let timeout = match handle.read_timeout { + Some(read_timeout) => { + let mut time = TimeSpec::default(); + syscall::clock_gettime(CLOCK_MONOTONIC, &mut time).map_err(|err| io::Error::from_raw_os_error(err.errno))?; + + let timeout = add_time(&time, &read_timeout); + self.time_file.write(&timeout)?; + Some(timeout) + }, + None => None + }; + + handle.todo_read.push_back((timeout, packet)); + }, + syscall::number::SYS_WRITE => { + packet.a = a; + + let timeout = match handle.write_timeout { + Some(write_timeout) => { + let mut time = TimeSpec::default(); + syscall::clock_gettime(CLOCK_MONOTONIC, &mut time).map_err(|err| io::Error::from_raw_os_error(err.errno))?; + + let timeout = add_time(&time, &write_timeout); + self.time_file.write(&timeout)?; + Some(timeout) + }, + None => None + }; + + handle.todo_write.push_back((timeout, 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 let Handle::Tcp(ref mut handle) = *handle { + 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 (_timeout, 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 (_timeout, 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| Error::new(err.raw_os_error().unwrap_or(EIO))); + 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 { + if let Handle::Tcp(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 let Handle::Tcp(ref mut handle) = *handle { + 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 = TcpHandle { + local: handle.local, + remote: (ip.header.src, tcp.header.src.get()), + flags: handle.flags, + events: 0, + read_timeout: handle.read_timeout, + write_timeout: handle.write_timeout, + ttl: handle.ttl, + 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, Handle::Tcp(new_handle))); + } + } + } + } + + for (packet, new_handle) in new_handles { + self.handles.insert(packet.a, new_handle); + self.scheme_file.write(&packet)?; + } + } + } + } + } + + Ok(()) + } + + fn time_event(&mut self) -> io::Result<()> { + let mut time = TimeSpec::default(); + if self.time_file.read(&mut time)? < mem::size_of::() { + return Err(io::Error::from_raw_os_error(EINVAL)); + } + + for (_id, handle) in self.handles.iter_mut() { + if let Handle::Tcp(ref mut handle) = *handle { + let mut i = 0; + while i < handle.todo_read.len() { + if let Some(timeout) = handle.todo_read.get(i).map(|e| e.0.clone()).unwrap_or(None) { + if time.tv_sec > timeout.tv_sec || (time.tv_sec == timeout.tv_sec && time.tv_nsec >= timeout.tv_nsec) { + let (_timeout, mut packet) = handle.todo_read.remove(i).unwrap(); + packet.a = (-ETIMEDOUT) as usize; + self.scheme_file.write(&packet)?; + } else { + i += 1; + } + } else { + i += 1; + } + } + + let mut i = 0; + while i < handle.todo_write.len() { + if let Some(timeout) = handle.todo_write.get(i).map(|e| e.0.clone()).unwrap_or(None) { + if time.tv_sec > timeout.tv_sec || (time.tv_sec == timeout.tv_sec && time.tv_nsec >= timeout.tv_nsec) { + let (_timeout, mut packet) = handle.todo_write.remove(i).unwrap(); + packet.a = (-ETIMEDOUT) as usize; + self.scheme_file.write(&packet)?; + } else { + i += 1; + } + } else { + i += 1; + } + } + } + } + + Ok(()) + } +} + +impl SchemeMut for Tcpd { + fn open(&mut self, url: &[u8], flags: usize, uid: u32, _gid: u32) -> Result { + let path = str::from_utf8(url).or(Err(Error::new(EINVAL)))?; + + let mut parts = path.split("/"); + let remote = parse_socket(parts.next().unwrap_or("")); + let mut local = parse_socket(parts.next().unwrap_or("")); + + if local.1 == 0 { + local.1 = self.rng.gen_range(32768, 65535); + } + + if local.1 <= 1024 && uid != 0 { + return Err(Error::new(EACCES)); + } + + if self.ports.contains_key(&local.1) { + return Err(Error::new(EADDRINUSE)); + } + + let mut handle = TcpHandle { + local: local, + remote: remote, + flags: flags, + events: 0, + read_timeout: None, + write_timeout: None, + ttl: 64, + 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| Error::new(err.raw_os_error().unwrap_or(EIO)))?; + + handle.seq += 1; + } + + self.ports.insert(local.1, 1); + + let id = self.next_id; + self.next_id += 1; + + self.handles.insert(id, Handle::Tcp(handle)); + + Ok(id) + } + + fn dup(&mut self, file: usize, buf: &[u8]) -> Result { + let handle = match *self.handles.get_mut(&file).ok_or(Error::new(EBADF))? { + Handle::Tcp(ref mut handle) => { + let mut new_handle = TcpHandle { + local: handle.local, + remote: handle.remote, + flags: handle.flags, + events: 0, + read_timeout: handle.read_timeout, + write_timeout: handle.write_timeout, + ttl: handle.ttl, + state: handle.state, + seq: handle.seq, + ack: handle.ack, + data: VecDeque::new(), + todo_dup: VecDeque::new(), + todo_read: VecDeque::new(), + todo_write: VecDeque::new(), + }; + + let path = str::from_utf8(buf).or(Err(Error::new(EINVAL)))?; + + if path == "ttl" { + Handle::Setting(file, SettingKind::Ttl) + } else if path == "read_timeout" { + Handle::Setting(file, SettingKind::ReadTimeout) + } else if path == "write_timeout" { + Handle::Setting(file, SettingKind::WriteTimeout) + } else 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| Error::new(err.raw_os_error().unwrap_or(EIO))).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 + } + }); + + Handle::Tcp(new_handle) + } else if path.is_empty() { + new_handle.data = handle.data.clone(); + + Handle::Tcp(new_handle) + } 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| Error::new(err.raw_os_error().unwrap_or(EIO))).and(Ok(buf.len()))?; + + new_handle.seq += 1; + + Handle::Tcp(new_handle) + } else { + return Err(Error::new(EINVAL)); + } + } + }, + Handle::Setting(file, kind) => { + Handle::Setting(file, kind) + } + }; + + let id = self.next_id; + self.next_id += 1; + + self.handles.insert(id, handle); + + Ok(id) + } + + fn read(&mut self, file: usize, buf: &mut [u8]) -> Result { + let (file, kind) = match *self.handles.get_mut(&file).ok_or(Error::new(EBADF))? { + Handle::Tcp(ref mut handle) => { + if ! handle.is_connected() { + return Err(Error::new(ENOTCONN)); + } else if let Some((ip, mut tcp)) = handle.data.pop_front() { + let len = std::cmp::min(buf.len(), tcp.data.len()); + for (i, c) in tcp.data.drain(0..len).enumerate() { + buf[i] = c; + } + if !tcp.data.is_empty() { + handle.data.push_front((ip, tcp)); + } + + return Ok(len); + } else if handle.flags & O_NONBLOCK == O_NONBLOCK || handle.read_closed() { + return Ok(0); + } else { + return Err(Error::new(EWOULDBLOCK)); + } + }, + Handle::Setting(file, kind) => { + (file, kind) + } + }; + + if let Handle::Tcp(ref mut handle) = *self.handles.get_mut(&file).ok_or(Error::new(EBADF))? { + let get_timeout = |timeout: &Option, buf: &mut [u8]| -> Result { + if let Some(ref timespec) = *timeout { + timespec.deref().read(buf).map_err(|err| Error::new(err.raw_os_error().unwrap_or(EIO))) + } else { + Ok(0) + } + }; + + match kind { + SettingKind::Ttl => { + if let Some(mut ttl) = buf.get_mut(0) { + *ttl = handle.ttl; + Ok(1) + } else { + Ok(0) + } + }, + SettingKind::ReadTimeout => { + get_timeout(&handle.read_timeout, buf) + }, + SettingKind::WriteTimeout => { + get_timeout(&handle.write_timeout, buf) + } + } + } else { + Err(Error::new(EBADF)) + } + } + + fn write(&mut self, file: usize, buf: &[u8]) -> Result { + let (file, kind) = match *self.handles.get_mut(&file).ok_or(Error::new(EBADF))? { + Handle::Tcp(ref mut handle) => { + if ! handle.is_connected() { + return Err(Error::new(ENOTCONN)); + } else if buf.len() >= 65507 { + return 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| Error::new(err.raw_os_error().unwrap_or(EIO)))?; + handle.seq += buf.len() as u32; + return Ok(buf.len()); + }, + _ => { + return Err(Error::new(EWOULDBLOCK)); + } + } + } + }, + Handle::Setting(file, kind) => { + (file, kind) + } + }; + + if let Handle::Tcp(ref mut handle) = *self.handles.get_mut(&file).ok_or(Error::new(EBADF))? { + let set_timeout = |timeout: &mut Option, buf: &[u8]| -> Result { + if buf.len() >= mem::size_of::() { + let mut timespec = TimeSpec::default(); + let count = timespec.deref_mut().write(buf).map_err(|err| Error::new(err.raw_os_error().unwrap_or(EIO)))?; + *timeout = Some(timespec); + Ok(count) + } else { + *timeout = None; + Ok(0) + } + }; + + match kind { + SettingKind::Ttl => { + if let Some(ttl) = buf.get(0) { + handle.ttl = *ttl; + Ok(1) + } else { + Ok(0) + } + }, + SettingKind::ReadTimeout => { + set_timeout(&mut handle.read_timeout, buf) + }, + SettingKind::WriteTimeout => { + set_timeout(&mut handle.write_timeout, buf) + } + } + } else { + Err(Error::new(EBADF)) + } + } + + fn fcntl(&mut self, file: usize, cmd: usize, arg: usize) -> Result { + if let Handle::Tcp(ref mut handle) = *self.handles.get_mut(&file).ok_or(Error::new(EBADF))? { + match cmd { + F_GETFL => Ok(handle.flags), + F_SETFL => { + handle.flags = arg & ! O_ACCMODE; + Ok(0) + }, + _ => Err(Error::new(EINVAL)) + } + } else { + Err(Error::new(EBADF)) + } + } + + fn fevent(&mut self, file: usize, flags: usize) -> Result { + if let Handle::Tcp(ref mut handle) = *self.handles.get_mut(&file).ok_or(Error::new(EBADF))? { + handle.events = flags; + Ok(file) + } else { + Err(Error::new(EBADF)) + } + } + + fn fpath(&mut self, file: usize, buf: &mut [u8]) -> Result { + if let Handle::Tcp(ref mut handle) = *self.handles.get_mut(&file).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) + } else { + Err(Error::new(EBADF)) + } + } + + fn fsync(&mut self, file: usize) -> Result { + let _handle = self.handles.get(&file).ok_or(Error::new(EBADF))?; + + Ok(0) + } + + fn close(&mut self, file: usize) -> Result { + let closed = { + if let Handle::Tcp(ref mut handle) = *self.handles.get_mut(&file).ok_or(Error::new(EBADF))? { + handle.data.clear(); + + 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| Error::new(err.raw_os_error().unwrap_or(EIO)))?; + + 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| Error::new(err.raw_os_error().unwrap_or(EIO)))?; + + handle.seq += 1; + + false + }, + _ => true + } + } else { + true + } + }; + + if closed { + if let Handle::Tcp(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 daemon(scheme_fd: usize, tcp_fd: usize, time_fd: usize) { + let scheme_file = unsafe { File::from_raw_fd(scheme_fd) }; + let tcp_file = unsafe { File::from_raw_fd(tcp_fd) }; + let time_file = unsafe { File::from_raw_fd(time_fd) }; + + let tcpd = Rc::new(RefCell::new(Tcpd::new(scheme_file, tcp_file, time_file))); + + let mut event_queue = EventQueue::<()>::new().expect("tcpd: failed to create event queue"); + + let time_tcpd = tcpd.clone(); + event_queue.add(time_fd, move |_count: usize| -> io::Result> { + time_tcpd.borrow_mut().time_event()?; + Ok(None) + }).expect("tcpd: failed to listen to events on time:"); + + let tcp_tcpd = tcpd.clone(); + event_queue.add(tcp_fd, move |_count: usize| -> io::Result> { + tcp_tcpd.borrow_mut().tcp_event()?; + Ok(None) + }).expect("tcpd: failed to listen to events on ip:6"); + + event_queue.add(scheme_fd, move |_count: usize| -> io::Result> { + tcpd.borrow_mut().scheme_event()?; + Ok(None) + }).expect("tcpd: failed to listen to events on :tcp"); + + event_queue.trigger_all(0).expect("tcpd: failed to trigger event queue"); + + event_queue.run().expect("tcpd: failed to run event queue"); +} + +fn main() { + let time_path = format!("time:{}", CLOCK_MONOTONIC); + match syscall::open(&time_path, O_RDWR) { + Ok(time_fd) => { + match syscall::open("ip:6", O_RDWR | O_NONBLOCK) { + Ok(tcp_fd) => { + // Daemonize + if unsafe { syscall::clone(0).unwrap() } == 0 { + match syscall::open(":tcp", O_RDWR | O_CREAT | O_NONBLOCK) { + Ok(scheme_fd) => { + daemon(scheme_fd, tcp_fd, time_fd); + }, + Err(err) => { + println!("tcpd: failed to create tcp scheme: {}", err); + process::exit(1); + } + } + } + }, + Err(err) => { + println!("tcpd: failed to open ip:6: {}", err); + process::exit(1); + } + } + }, + Err(err) => { + println!("tcpd: failed to open {}: {}", time_path, err); + process::exit(1); + } + } +} diff --git a/src/udpd/main.rs b/src/udpd/main.rs new file mode 100644 index 0000000000..23d6479af7 --- /dev/null +++ b/src/udpd/main.rs @@ -0,0 +1,586 @@ +extern crate event; +extern crate netutils; +extern crate rand; +extern crate syscall; + +use rand::{Rng, OsRng}; +use std::collections::{BTreeMap, VecDeque}; +use std::cell::RefCell; +use std::fs::File; +use std::io::{self, Read, Write}; +use std::{mem, process, slice, str}; +use std::ops::{Deref, DerefMut}; +use std::os::unix::io::FromRawFd; +use std::rc::Rc; + +use event::EventQueue; +use netutils::{n16, Ipv4, Ipv4Addr, Ipv4Header, Checksum}; +use netutils::udp::{Udp, UdpHeader}; +use syscall::data::{Packet, TimeSpec}; +use syscall::error::{Error, Result, EACCES, EADDRINUSE, EBADF, EIO, EINVAL, EMSGSIZE, ENOTCONN, ETIMEDOUT, EWOULDBLOCK}; +use syscall::flag::{CLOCK_MONOTONIC, EVENT_READ, F_GETFL, F_SETFL, O_ACCMODE, O_CREAT, O_RDWR, O_NONBLOCK}; +use syscall::number::{SYS_READ, SYS_WRITE}; +use syscall::scheme::SchemeMut; + +fn add_time(a: &TimeSpec, b: &TimeSpec) -> TimeSpec { + let mut secs = a.tv_sec + b.tv_sec; + + let mut nsecs = a.tv_nsec + b.tv_nsec; + while nsecs >= 1000000000 { + nsecs -= 1000000000; + secs += 1; + } + + TimeSpec { + tv_sec: secs, + tv_nsec: nsecs + } +} + +fn parse_socket(socket: &str) -> (Ipv4Addr, u16) { + let mut socket_parts = socket.split(":"); + let host = Ipv4Addr::from_str(socket_parts.next().unwrap_or("")); + let port = socket_parts.next().unwrap_or("").parse::().unwrap_or(0); + (host, port) +} + +struct UdpHandle { + local: (Ipv4Addr, u16), + remote: (Ipv4Addr, u16), + flags: usize, + events: usize, + read_timeout: Option, + write_timeout: Option, + ttl: u8, + data: VecDeque>, + todo: VecDeque<(Option, Packet)>, +} + +#[derive(Copy, Clone)] +enum SettingKind { + Ttl, + ReadTimeout, + WriteTimeout +} + +enum Handle { + Udp(UdpHandle), + Setting(usize, SettingKind), +} + +struct Udpd { + scheme_file: File, + udp_file: File, + time_file: File, + ports: BTreeMap, + next_id: usize, + handles: BTreeMap, + rng: OsRng, +} + +impl Udpd { + fn new(scheme_file: File, udp_file: File, time_file: File) -> Self { + Udpd { + scheme_file: scheme_file, + udp_file: udp_file, + time_file: time_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) { + if let Handle::Udp(ref mut handle) = *handle { + let timeout = match packet.a { + SYS_READ => match handle.read_timeout { + Some(read_timeout) => { + let mut time = TimeSpec::default(); + syscall::clock_gettime(CLOCK_MONOTONIC, &mut time).map_err(|err| io::Error::from_raw_os_error(err.errno))?; + + let timeout = add_time(&time, &read_timeout); + self.time_file.write(&timeout)?; + Some(timeout) + }, + None => None + }, + SYS_WRITE => match handle.write_timeout { + Some(write_timeout) => { + let mut time = TimeSpec::default(); + syscall::clock_gettime(CLOCK_MONOTONIC, &mut time).map_err(|err| io::Error::from_raw_os_error(err.errno))?; + + let timeout = add_time(&time, &write_timeout); + self.time_file.write(&timeout)?; + Some(timeout) + }, + None => None + }, + _ => None + }; + + handle.todo.push_back((timeout, 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() { + if let Handle::Udp(ref mut handle) = *handle { + // 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 (_timeout, 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(()) + } + + fn time_event(&mut self) -> io::Result<()> { + let mut time = TimeSpec::default(); + if self.time_file.read(&mut time)? < mem::size_of::() { + return Err(io::Error::from_raw_os_error(EINVAL)); + } + + for (_id, handle) in self.handles.iter_mut() { + if let Handle::Udp(ref mut handle) = *handle { + let mut i = 0; + while i < handle.todo.len() { + if let Some(timeout) = handle.todo.get(i).map(|e| e.0.clone()).unwrap_or(None) { + if time.tv_sec > timeout.tv_sec || (time.tv_sec == timeout.tv_sec && time.tv_nsec >= timeout.tv_nsec) { + let (_timeout, mut packet) = handle.todo.remove(i).unwrap(); + packet.a = (-ETIMEDOUT) as usize; + self.scheme_file.write(&packet)?; + } else { + i += 1; + } + } else { + i += 1; + } + } + } + } + + Ok(()) + } +} + +impl SchemeMut for Udpd { + fn open(&mut self, url: &[u8], flags: usize, uid: u32, _gid: u32) -> Result { + let path = str::from_utf8(url).or(Err(Error::new(EINVAL)))?; + + let mut parts = path.split("/"); + let remote = parse_socket(parts.next().unwrap_or("")); + let mut local = parse_socket(parts.next().unwrap_or("")); + + if local.1 == 0 { + local.1 = self.rng.gen_range(32768, 65535); + } + + if local.1 <= 1024 && uid != 0 { + return Err(Error::new(EACCES)); + } + + if self.ports.contains_key(&local.1) { + return Err(Error::new(EADDRINUSE)); + } + + self.ports.insert(local.1, 1); + + let id = self.next_id; + self.next_id += 1; + + self.handles.insert(id, Handle::Udp(UdpHandle { + local: local, + remote: remote, + flags: flags, + events: 0, + ttl: 64, + read_timeout: None, + write_timeout: None, + data: VecDeque::new(), + todo: VecDeque::new(), + })); + + Ok(id) + } + + fn dup(&mut self, file: usize, buf: &[u8]) -> Result { + let handle = match *self.handles.get(&file).ok_or(Error::new(EBADF))? { + Handle::Udp(ref handle) => { + let mut handle = UdpHandle { + local: handle.local, + remote: handle.remote, + flags: handle.flags, + events: 0, + ttl: handle.ttl, + read_timeout: handle.read_timeout, + write_timeout: handle.write_timeout, + data: handle.data.clone(), + todo: VecDeque::new(), + }; + + let path = str::from_utf8(buf).or(Err(Error::new(EINVAL)))?; + + if path == "ttl" { + Handle::Setting(file, SettingKind::Ttl) + } else if path == "read_timeout" { + Handle::Setting(file, SettingKind::ReadTimeout) + } else if path == "write_timeout" { + Handle::Setting(file, SettingKind::WriteTimeout) + } else { + 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; + } + + Handle::Udp(handle) + } + }, + Handle::Setting(file, kind) => { + Handle::Setting(file, kind) + } + }; + + let id = self.next_id; + self.next_id += 1; + + self.handles.insert(id, handle); + + Ok(id) + } + + fn read(&mut self, file: usize, buf: &mut [u8]) -> Result { + let (file, kind) = match *self.handles.get_mut(&file).ok_or(Error::new(EBADF))? { + Handle::Udp(ref mut handle) => { + if handle.remote.0 == Ipv4Addr::NULL || handle.remote.1 == 0 { + return 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; + } + + return Ok(i); + } else if handle.flags & O_NONBLOCK == O_NONBLOCK { + return Ok(0); + } else { + return Err(Error::new(EWOULDBLOCK)); + } + }, + Handle::Setting(file, kind) => { + (file, kind) + } + }; + + if let Handle::Udp(ref mut handle) = *self.handles.get_mut(&file).ok_or(Error::new(EBADF))? { + let get_timeout = |timeout: &Option, buf: &mut [u8]| -> Result { + if let Some(ref timespec) = *timeout { + timespec.deref().read(buf).map_err(|err| Error::new(err.raw_os_error().unwrap_or(EIO))) + } else { + Ok(0) + } + }; + + match kind { + SettingKind::Ttl => { + if let Some(mut ttl) = buf.get_mut(0) { + *ttl = handle.ttl; + Ok(1) + } else { + Ok(0) + } + }, + SettingKind::ReadTimeout => { + get_timeout(&handle.read_timeout, buf) + }, + SettingKind::WriteTimeout => { + get_timeout(&handle.write_timeout, buf) + } + } + } else { + Err(Error::new(EBADF)) + } + } + + fn write(&mut self, file: usize, buf: &[u8]) -> Result { + let (file, kind) = match *self.handles.get(&file).ok_or(Error::new(EBADF))? { + Handle::Udp(ref handle) => { + if handle.remote.0 == Ipv4Addr::NULL || handle.remote.1 == 0 { + return Err(Error::new(ENOTCONN)); + } else if buf.len() >= 65507 { + return Err(Error::new(EMSGSIZE)); + } else { + let udp_data = buf.to_vec(); + + let udp = Udp { + header: UdpHeader { + src: n16::new(handle.local.1), + dst: n16::new(handle.remote.1), + len: n16::new((udp_data.len() + mem::size_of::()) as u16), + checksum: Checksum { data: 0 } + }, + data: udp_data + }; + + let ip_data = udp.to_bytes(); + + let ip = Ipv4 { + header: Ipv4Header { + ver_hlen: 0x45, + services: 0, + len: n16::new((ip_data.len() + mem::size_of::()) as u16), + id: n16::new(self.rng.gen()), + flags_fragment: n16::new(0), + ttl: handle.ttl, + proto: 0x11, + checksum: Checksum { data: 0 }, + src: handle.local.0, + dst: handle.remote.0 + }, + options: Vec::new(), + data: ip_data + }; + + return self.udp_file.write(&ip.to_bytes()).map_err(|err| Error::new(err.raw_os_error().unwrap_or(EIO))).and(Ok(buf.len())); + } + }, + Handle::Setting(file, kind) => { + (file, kind) + } + }; + + if let Handle::Udp(ref mut handle) = *self.handles.get_mut(&file).ok_or(Error::new(EBADF))? { + let set_timeout = |timeout: &mut Option, buf: &[u8]| -> Result { + if buf.len() >= mem::size_of::() { + let mut timespec = TimeSpec::default(); + let count = timespec.deref_mut().write(buf).map_err(|err| Error::new(err.raw_os_error().unwrap_or(EIO)))?; + *timeout = Some(timespec); + Ok(count) + } else { + *timeout = None; + Ok(0) + } + }; + + match kind { + SettingKind::Ttl => { + if let Some(ttl) = buf.get(0) { + handle.ttl = *ttl; + Ok(1) + } else { + Ok(0) + } + }, + SettingKind::ReadTimeout => { + set_timeout(&mut handle.read_timeout, buf) + }, + SettingKind::WriteTimeout => { + set_timeout(&mut handle.write_timeout, buf) + } + } + } else { + Err(Error::new(EBADF)) + } + } + + fn fcntl(&mut self, file: usize, cmd: usize, arg: usize) -> Result { + if let Handle::Udp(ref mut handle) = *self.handles.get_mut(&file).ok_or(Error::new(EBADF))? { + match cmd { + F_GETFL => Ok(handle.flags), + F_SETFL => { + handle.flags = arg & ! O_ACCMODE; + Ok(0) + }, + _ => Err(Error::new(EINVAL)) + } + } else { + Err(Error::new(EBADF)) + } + } + + fn fevent(&mut self, file: usize, flags: usize) -> Result { + if let Handle::Udp(ref mut handle) = *self.handles.get_mut(&file).ok_or(Error::new(EBADF))? { + handle.events = flags; + Ok(file) + } else { + Err(Error::new(EBADF)) + } + } + + fn fpath(&mut self, file: usize, buf: &mut [u8]) -> Result { + if let Handle::Udp(ref mut handle) = *self.handles.get_mut(&file).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) + } else { + Err(Error::new(EBADF)) + } + } + + fn fsync(&mut self, file: usize) -> Result { + let _handle = self.handles.get(&file).ok_or(Error::new(EBADF))?; + + Ok(0) + } + + fn close(&mut self, file: usize) -> Result { + let handle = self.handles.remove(&file).ok_or(Error::new(EBADF))?; + + if let Handle::Udp(ref handle) = handle { + 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 daemon(scheme_fd: usize, udp_fd: usize, time_fd: usize) { + let scheme_file = unsafe { File::from_raw_fd(scheme_fd) }; + let udp_file = unsafe { File::from_raw_fd(udp_fd) }; + let time_file = unsafe { File::from_raw_fd(time_fd) }; + + let udpd = Rc::new(RefCell::new(Udpd::new(scheme_file, udp_file, time_file))); + + let mut event_queue = EventQueue::<()>::new().expect("udpd: failed to create event queue"); + + let time_udpd = udpd.clone(); + event_queue.add(time_fd, move |_count: usize| -> io::Result> { + time_udpd.borrow_mut().time_event()?; + Ok(None) + }).expect("udpd: failed to listen to events on time:"); + + let udp_udpd = udpd.clone(); + event_queue.add(udp_fd, move |_count: usize| -> io::Result> { + udp_udpd.borrow_mut().udp_event()?; + Ok(None) + }).expect("udpd: failed to listen to events on ip:11"); + + event_queue.add(scheme_fd, move |_count: usize| -> io::Result> { + udpd.borrow_mut().scheme_event()?; + Ok(None) + }).expect("udpd: failed to listen to events on :udp"); + + event_queue.trigger_all(0).expect("udpd: failed to trigger event queue"); + + event_queue.run().expect("udpd: failed to run event queue"); +} + +fn main() { + let time_path = format!("time:{}", CLOCK_MONOTONIC); + match syscall::open(&time_path, O_RDWR) { + Ok(time_fd) => { + match syscall::open("ip:11", O_RDWR | O_NONBLOCK) { + Ok(udp_fd) => { + // Daemonize + if unsafe { syscall::clone(0).unwrap() } == 0 { + match syscall::open(":udp", O_RDWR | O_CREAT | O_NONBLOCK) { + Ok(scheme_fd) => { + daemon(scheme_fd, udp_fd, time_fd); + }, + Err(err) => { + println!("udpd: failed to create udp scheme: {}", err); + process::exit(1); + } + } + } + }, + Err(err) => { + println!("udpd: failed to open ip:11: {}", err); + process::exit(1); + } + } + }, + Err(err) => { + println!("udpd: failed to open {}: {}", time_path, err); + process::exit(1); + } + } +}