From 05650efcb170f209552f544a7c4a8ee708d5449c Mon Sep 17 00:00:00 2001 From: Egor Karavaev Date: Tue, 19 Sep 2017 00:42:37 +0300 Subject: [PATCH] Split scheme.rs. --- src/smolnetd/device.rs | 11 +- src/smolnetd/main.rs | 11 +- src/smolnetd/scheme.rs | 469 ------------------------------------- src/smolnetd/scheme/ip.rs | 148 ++++++++++++ src/smolnetd/scheme/mod.rs | 205 ++++++++++++++++ src/smolnetd/scheme/udp.rs | 171 ++++++++++++++ 6 files changed, 536 insertions(+), 479 deletions(-) delete mode 100644 src/smolnetd/scheme.rs create mode 100644 src/smolnetd/scheme/ip.rs create mode 100644 src/smolnetd/scheme/mod.rs create mode 100644 src/smolnetd/scheme/udp.rs diff --git a/src/smolnetd/device.rs b/src/smolnetd/device.rs index 5589fc51b9..37cbb9d5c0 100644 --- a/src/smolnetd/device.rs +++ b/src/smolnetd/device.rs @@ -1,9 +1,10 @@ -use std::rc::Rc; -use std::fs::File; -use std::cell::RefCell; -use std::io::Write; -use std::collections::VecDeque; use smoltcp; +use std::cell::RefCell; +use std::collections::VecDeque; +use std::fs::File; +use std::io::Write; +use std::rc::Rc; + use buffer_pool::Buffer; pub struct NetworkDevice { diff --git a/src/smolnetd/main.rs b/src/smolnetd/main.rs index 4b84242e03..77dcc103f3 100644 --- a/src/smolnetd/main.rs +++ b/src/smolnetd/main.rs @@ -5,20 +5,21 @@ extern crate netutils; extern crate smoltcp; extern crate syscall; -use error::{Error, Result}; -use event::EventQueue; -use scheme::Smolnetd; use std::cell::RefCell; use std::fs::File; use std::os::unix::io::{FromRawFd, RawFd}; use std::process; use std::rc::Rc; -mod error; +use error::{Error, Result}; +use event::EventQueue; +use scheme::Smolnetd; + mod buffer_pool; mod device; -mod scheme; +mod error; mod logger; +mod scheme; fn run() -> Result<()> { use syscall::flag::*; diff --git a/src/smolnetd/scheme.rs b/src/smolnetd/scheme.rs deleted file mode 100644 index ac8596128d..0000000000 --- a/src/smolnetd/scheme.rs +++ /dev/null @@ -1,469 +0,0 @@ -use netutils::{getcfg, MacAddr}; -use smoltcp; -use std::collections::{BTreeMap, VecDeque}; -use std::fs::File; -use std::io::{Read, Write}; -use std::mem; -use std::net::Ipv4Addr; -use std::str::FromStr; -use std::time::Instant; -use std::rc::Rc; -use std::cell::RefCell; -use smoltcp::socket::AsSocket; -use syscall::SchemeMut; -use syscall; - -use device::NetworkDevice; -use error::{Error, Result}; -use buffer_pool::{Buffer, BufferPool}; - -struct RawHandle { - flags: usize, - events: usize, - socket_handle: smoltcp::socket::SocketHandle, -} - -struct UdpHandle { - flags: usize, - events: usize, - remote_endpoint: smoltcp::wire::IpEndpoint, - socket_handle: smoltcp::socket::SocketHandle, -} - -pub struct Smolnetd { - network_file: Rc>, - ip_file: File, - udp_file: File, - time_file: File, - - iface: smoltcp::iface::EthernetInterface<'static, 'static, 'static, NetworkDevice>, - socket_set: smoltcp::socket::SocketSet<'static, 'static, 'static>, - - startup_time: Instant, - next_fd: usize, - - raw_sockets: BTreeMap, - udp_sockets: BTreeMap, - - input_queue: Rc>>, - input_buffer_pool: BufferPool, -} - -struct IpScheme<'a>(&'a mut Smolnetd); -struct UdpScheme<'a>(&'a mut Smolnetd); - -impl Smolnetd { - const INGRESS_PACKET_SIZE: usize = 2048; - const SOCKET_BUFFER_SIZE: usize = 128; //packets - const CHECK_TIMEOUT_MS: i64 = 1000; - - pub fn new(network_file: File, ip_file: File, udp_file: File, time_file: File) -> Smolnetd { - let arp_cache = smoltcp::iface::SliceArpCache::new(vec![Default::default(); 8]); - //TODO Use smoltcp::wire::EthernetAddress::from_str - let mac_addr = MacAddr::from_str(&getcfg("mac").unwrap().trim()); - let hardware_addr = smoltcp::wire::EthernetAddress(mac_addr.bytes); - //TODO Use smoltcp::wire::Ipv4Addr::from_str - let ip_bytes = Ipv4Addr::from_str(&getcfg("ip").unwrap().trim()) - .unwrap() - .octets(); - let protocol_addrs = [ - smoltcp::wire::IpAddress::Ipv4(smoltcp::wire::Ipv4Address::from_bytes(&ip_bytes)), - ]; - let default_gw = smoltcp::wire::IpAddress::Ipv4(smoltcp::wire::Ipv4Address::from_bytes( - &Ipv4Addr::from_str(&getcfg("ip_router").unwrap().trim()) - .unwrap() - .octets(), - )); - trace!("mac {:?} ip {:?}", hardware_addr, protocol_addrs); - let input_queue = Rc::new(RefCell::new(VecDeque::new())); - let network_file = Rc::new(RefCell::new(network_file)); - let network_device = NetworkDevice::new(network_file.clone(), input_queue.clone()); - let mut iface = smoltcp::iface::EthernetInterface::new( - Box::new(network_device), - Box::new(arp_cache) as Box, - hardware_addr, - protocol_addrs, - ); - iface.set_default_gateway(24, Some(default_gw)); - Smolnetd { - iface, - socket_set: smoltcp::socket::SocketSet::new(vec![]), - startup_time: Instant::now(), - ip_file, - udp_file, - time_file, - raw_sockets: BTreeMap::new(), - udp_sockets: BTreeMap::new(), - next_fd: 0, - input_queue, - network_file, - input_buffer_pool: BufferPool::new(Self::INGRESS_PACKET_SIZE), - } - } - - pub fn on_network_scheme_event(&mut self) -> Result> { - if self.read_frames()? > 0 { - self.poll().map(Some)?; - } - Ok(None) - } - - pub fn on_ip_scheme_event(&mut self) -> Result> { - loop { - let mut packet = syscall::Packet::default(); - if self.ip_file.read(&mut packet)? == 0 { - break; - } - IpScheme(self).handle(&mut packet); - self.ip_file.write_all(&packet)?; - } - Ok(None) - } - - pub fn on_udp_scheme_event(&mut self) -> Result> { - loop { - let mut packet = syscall::Packet::default(); - if self.udp_file.read(&mut packet)? == 0 { - break; - } - UdpScheme(self).handle(&mut packet); - self.udp_file.write_all(&packet)?; - } - Ok(None) - } - - pub fn on_time_event(&mut self) -> Result> { - let mut time = syscall::data::TimeSpec::default(); - if self.time_file.read(&mut time)? < mem::size_of::() { - panic!(); - } - let mut time_ms = time.tv_sec * 1000i64 + (time.tv_nsec as i64) / 1_000_000i64; - time_ms += Smolnetd::CHECK_TIMEOUT_MS; - time.tv_sec = time_ms / 1000; - time.tv_nsec = ((time_ms % 1000) * 1_000_00) as i32; - self.time_file - .write_all(&time) - .map_err(|e| Error::from_io_error(e, "Failed to write to time file"))?; - - self.poll().map(Some)?; - Ok(None) - } - - fn poll(&mut self) -> Result<()> { - let timestamp = self.get_timestamp(); - self.iface - .poll(&mut self.socket_set, timestamp) - .expect("poll error"); - self.notify_raw_sockets() - } - - fn read_frames(&mut self) -> Result { - let mut total_frames = 0; - loop { - let mut buffer = self.input_buffer_pool.get_buffer(); - let count = self.network_file - .borrow_mut() - .read(&mut buffer) - .map_err(|e| { - Error::from_io_error(e, "Failed to read from network file") - })?; - if count == 0 { - break; - } - trace!("got frame {}", count); - buffer.resize(count); - self.input_queue.borrow_mut().push_back(buffer); - total_frames += 1; - } - Ok(total_frames) - } - - fn get_timestamp(&self) -> u64 { - let duration = Instant::now().duration_since(self.startup_time); - let duration_ms = (duration.as_secs() * 1000) + (duration.subsec_nanos() / 1000000) as u64; - duration_ms - } - - fn network_fsync(&mut self) -> syscall::Result { - use std::os::unix::io::AsRawFd; - syscall::fsync(self.network_file.borrow_mut().as_raw_fd() as usize) - } - - fn notify_raw_sockets(&mut self) -> Result<()> { - for (&fd, ref handle) in &self.raw_sockets { - let socket: &mut smoltcp::socket::RawSocket = - self.socket_set.get_mut(handle.socket_handle).as_socket(); - if socket.can_send() { - post_fevent(&mut self.ip_file, fd, syscall::EVENT_READ, 1)?; - } - } - Ok(()) - } -} - -impl<'a> syscall::SchemeMut for IpScheme<'a> { - fn open(&mut self, url: &[u8], flags: usize, uid: u32, _gid: u32) -> syscall::Result { - use std::str; - - if uid != 0 { - return Err(syscall::Error::new(syscall::EACCES)); - } - let path = str::from_utf8(url).or_else(|_| Err(syscall::Error::new(syscall::EINVAL)))?; - let proto = u8::from_str_radix(path, 16).or(Err(syscall::Error::new(syscall::ENOENT)))?; - - let mut rx_packets = Vec::with_capacity(Smolnetd::SOCKET_BUFFER_SIZE); - let mut tx_packets = Vec::with_capacity(Smolnetd::SOCKET_BUFFER_SIZE); - for _ in 0..Smolnetd::SOCKET_BUFFER_SIZE { - rx_packets.push(smoltcp::socket::RawPacketBuffer::new( - vec![0; NetworkDevice::MTU], - )); - tx_packets.push(smoltcp::socket::RawPacketBuffer::new( - vec![0; NetworkDevice::MTU], - )); - } - let rx_buffer = smoltcp::socket::RawSocketBuffer::new(rx_packets); - let tx_buffer = smoltcp::socket::RawSocketBuffer::new(tx_packets); - let raw_socket = smoltcp::socket::RawSocket::new( - smoltcp::wire::IpVersion::Ipv4, - smoltcp::wire::IpProtocol::from(proto), - rx_buffer, - tx_buffer, - ); - - let socket_handle = self.0.socket_set.add(raw_socket); - let id = self.0.next_fd; - trace!("Open {} -> {}", path, id); - - self.0.raw_sockets.insert( - id, - RawHandle { - flags, - events: 0, - socket_handle, - }, - ); - self.0.next_fd += 1; - Ok(id) - } - - fn close(&mut self, fd: usize) -> syscall::Result { - trace!("Close {}", fd); - let socket_handle = { - let handle = self.0 - .raw_sockets - .get(&fd) - .ok_or_else(|| syscall::Error::new(syscall::EBADF))?; - handle.socket_handle - }; - self.0.raw_sockets.remove(&fd); - self.0.socket_set.remove(socket_handle); - Ok(0) - } - - fn write(&mut self, fd: usize, buf: &[u8]) -> syscall::Result { - trace!("Write {} len {}", fd, buf.len()); - - let handle = self.0 - .raw_sockets - .get(&fd) - .ok_or_else(|| syscall::Error::new(syscall::EBADF))?; - let socket: &mut smoltcp::socket::RawSocket = - self.0.socket_set.get_mut(handle.socket_handle).as_socket(); - socket.send_slice(buf).expect("Can't send slice"); - Ok(buf.len()) - } - - fn read(&mut self, fd: usize, buf: &mut [u8]) -> syscall::Result { - use smoltcp::socket::AsSocket; - - let handle = self.0 - .raw_sockets - .get(&fd) - .ok_or_else(|| syscall::Error::new(syscall::EBADF))?; - let socket: &mut smoltcp::socket::RawSocket = - self.0.socket_set.get_mut(handle.socket_handle).as_socket(); - if socket.can_recv() { - let length = socket.recv_slice(buf).expect("Can't receive slice"); - trace!("Read fd {} len {}", fd, length); - Ok(length) - } else if handle.flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK { - Ok(0) - } else { - Err(syscall::Error::new(syscall::EWOULDBLOCK)) - } - } - - fn fevent(&mut self, fd: usize, events: usize) -> syscall::Result { - trace!("fevent {}", fd); - let handle = self.0 - .raw_sockets - .get_mut(&fd) - .ok_or_else(|| syscall::Error::new(syscall::EBADF))?; - handle.events = events; - Ok(fd) - } - - fn fsync(&mut self, fd: usize) -> syscall::Result { - trace!("fsync {}", fd); - { - let _handle = self.0 - .raw_sockets - .get_mut(&fd) - .ok_or_else(|| syscall::Error::new(syscall::EBADF))?; - } - self.0.network_fsync() - } -} - -impl<'a> syscall::SchemeMut for UdpScheme<'a> { - fn open(&mut self, url: &[u8], flags: usize, uid: u32, _gid: u32) -> syscall::Result { - use std::str; - - if uid != 0 { - return Err(syscall::Error::new(syscall::EACCES)); - } - let path = str::from_utf8(url).or_else(|_| Err(syscall::Error::new(syscall::EINVAL)))?; - let mut parts = path.split("/"); - let (remote_ip, remote_port) = parse_socket(parts.next().unwrap_or("")); - let (local_ip, local_port) = parse_socket(parts.next().unwrap_or("")); - - let mut rx_packets = Vec::with_capacity(Smolnetd::SOCKET_BUFFER_SIZE); - let mut tx_packets = Vec::with_capacity(Smolnetd::SOCKET_BUFFER_SIZE); - for _ in 0..Smolnetd::SOCKET_BUFFER_SIZE { - rx_packets.push(smoltcp::socket::UdpPacketBuffer::new( - vec![0; NetworkDevice::MTU], - )); - tx_packets.push(smoltcp::socket::UdpPacketBuffer::new( - vec![0; NetworkDevice::MTU], - )); - } - let rx_buffer = smoltcp::socket::UdpSocketBuffer::new(rx_packets); - let tx_buffer = smoltcp::socket::UdpSocketBuffer::new(tx_packets); - let mut udp_socket = smoltcp::socket::UdpSocket::new(rx_buffer, tx_buffer); - - if !local_ip.is_unspecified() && local_port != 0 { - let udp_socket: &mut smoltcp::socket::UdpSocket = udp_socket.as_socket(); - udp_socket.bind(smoltcp::wire::IpEndpoint::new( - smoltcp::wire::IpAddress::Ipv4( - smoltcp::wire::Ipv4Address::from_bytes(&local_ip.octets()), - ), - local_port, - )).unwrap(); - } - - let socket_handle = self.0.socket_set.add(udp_socket); - let id = self.0.next_fd; - trace!("Open {} -> {}", path, id); - - self.0.udp_sockets.insert( - id, - UdpHandle { - flags, - events: 0, - socket_handle, - remote_endpoint: smoltcp::wire::IpEndpoint::new( - smoltcp::wire::IpAddress::Ipv4( - smoltcp::wire::Ipv4Address::from_bytes(&remote_ip.octets()), - ), - remote_port, - ), - }, - ); - self.0.next_fd += 1; - Ok(id) - } - - fn close(&mut self, fd: usize) -> syscall::Result { - trace!("Close {}", fd); - let socket_handle = { - let handle = self.0 - .udp_sockets - .get(&fd) - .ok_or_else(|| syscall::Error::new(syscall::EBADF))?; - handle.socket_handle - }; - self.0.udp_sockets.remove(&fd); - self.0.socket_set.remove(socket_handle); - Ok(0) - } - - fn write(&mut self, fd: usize, buf: &[u8]) -> syscall::Result { - trace!("Write {} len {}", fd, buf.len()); - - let handle = self.0 - .udp_sockets - .get(&fd) - .ok_or_else(|| syscall::Error::new(syscall::EBADF))?; - let socket: &mut smoltcp::socket::UdpSocket = - self.0.socket_set.get_mut(handle.socket_handle).as_socket(); - socket.send_slice(buf, handle.remote_endpoint).expect("Can't send slice"); - Ok(buf.len()) - } - - fn read(&mut self, fd: usize, buf: &mut [u8]) -> syscall::Result { - trace!("Read {}", fd); - - let handle = self.0 - .udp_sockets - .get(&fd) - .ok_or_else(|| syscall::Error::new(syscall::EBADF))?; - let socket: &mut smoltcp::socket::UdpSocket = - self.0.socket_set.get_mut(handle.socket_handle).as_socket(); - if socket.can_recv() { - let (length, _) = socket.recv_slice(buf).expect("Can't receive slice"); - Ok(length) - } else if handle.flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK { - Ok(0) - } else { - Err(syscall::Error::new(syscall::EWOULDBLOCK)) - } - } - - fn fevent(&mut self, fd: usize, events: usize) -> syscall::Result { - trace!("fevent {}", fd); - let handle = self.0 - .udp_sockets - .get_mut(&fd) - .ok_or_else(|| syscall::Error::new(syscall::EBADF))?; - handle.events = events; - Ok(fd) - } - - fn fsync(&mut self, fd: usize) -> syscall::Result { - trace!("fsync {}", fd); - { - let _handle = self.0 - .udp_sockets - .get_mut(&fd) - .ok_or_else(|| syscall::Error::new(syscall::EBADF))?; - } - self.0.network_fsync() - } -} - -fn post_fevent(scheme_file: &mut File, fd: usize, event: usize, data_len: usize) -> Result<()> { - scheme_file - .write(&syscall::Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: fd, - c: event, - d: data_len, - }) - .map(|_| ()) - .map_err(|e| Error::from_io_error(e, "failed to post fevent")) -} - -fn parse_socket(socket: &str) -> (Ipv4Addr, u16) { - let mut socket_parts = socket.split(":"); - let host = Ipv4Addr::from_str(socket_parts.next().unwrap_or("")).unwrap(); - let port = socket_parts - .next() - .unwrap_or("") - .parse::() - .unwrap_or(0); - (host, port) -} diff --git a/src/smolnetd/scheme/ip.rs b/src/smolnetd/scheme/ip.rs new file mode 100644 index 0000000000..9264d58006 --- /dev/null +++ b/src/smolnetd/scheme/ip.rs @@ -0,0 +1,148 @@ +use smoltcp::socket::{AsSocket, RawPacketBuffer, RawSocket, RawSocketBuffer, SocketHandle}; +use smoltcp::wire::{IpProtocol, IpVersion}; +use std::collections::BTreeMap; +use syscall; + +use device::NetworkDevice; +use error::Result; +use super::{Smolnetd, SocketSet}; + +pub struct RawHandle { + flags: usize, + events: usize, + socket_handle: SocketHandle, +} + +pub struct IpScheme { + next_ip_fd: usize, + raw_sockets: BTreeMap, + socket_set: SocketSet, +} + +impl IpScheme { + pub fn new(socket_set: SocketSet) -> IpScheme { + IpScheme { + next_ip_fd: 1, + raw_sockets: BTreeMap::new(), + socket_set, + } + } + + pub fn notify_ready_sockets Result<()>>(&self, mut f: F) -> Result<()> { + for (&fd, ref handle) in &self.raw_sockets { + let mut socket_set = self.socket_set.borrow_mut(); + let socket: &mut RawSocket = socket_set.get_mut(handle.socket_handle).as_socket(); + if socket.can_send() { + f(fd)? + } + } + Ok(()) + } +} + +impl<'a> syscall::SchemeMut for IpScheme { + fn open(&mut self, url: &[u8], flags: usize, uid: u32, _gid: u32) -> syscall::Result { + use std::str; + + if uid != 0 { + return Err(syscall::Error::new(syscall::EACCES)); + } + let path = str::from_utf8(url).or_else(|_| Err(syscall::Error::new(syscall::EINVAL)))?; + let proto = u8::from_str_radix(path, 16).or(Err(syscall::Error::new(syscall::ENOENT)))?; + + let mut rx_packets = Vec::with_capacity(Smolnetd::SOCKET_BUFFER_SIZE); + let mut tx_packets = Vec::with_capacity(Smolnetd::SOCKET_BUFFER_SIZE); + for _ in 0..Smolnetd::SOCKET_BUFFER_SIZE { + rx_packets.push(RawPacketBuffer::new(vec![0; NetworkDevice::MTU])); + tx_packets.push(RawPacketBuffer::new(vec![0; NetworkDevice::MTU])); + } + let rx_buffer = RawSocketBuffer::new(rx_packets); + let tx_buffer = RawSocketBuffer::new(tx_packets); + let raw_socket = RawSocket::new( + IpVersion::Ipv4, + IpProtocol::from(proto), + rx_buffer, + tx_buffer, + ); + + let socket_handle = self.socket_set.borrow_mut().add(raw_socket); + let id = self.next_ip_fd; + trace!("IP Open {} -> {}", path, id); + + self.raw_sockets.insert( + id, + RawHandle { + flags, + events: 0, + socket_handle, + }, + ); + self.next_ip_fd += 1; + Ok(id) + } + + fn close(&mut self, fd: usize) -> syscall::Result { + trace!("IP Close {}", fd); + let socket_handle = { + let handle = self.raw_sockets + .get(&fd) + .ok_or_else(|| syscall::Error::new(syscall::EBADF))?; + handle.socket_handle + }; + self.raw_sockets.remove(&fd); + self.socket_set.borrow_mut().remove(socket_handle); + Ok(0) + } + + fn write(&mut self, fd: usize, buf: &[u8]) -> syscall::Result { + trace!("IP Write {} len {}", fd, buf.len()); + + let handle = self.raw_sockets + .get(&fd) + .ok_or_else(|| syscall::Error::new(syscall::EBADF))?; + let mut socket_set = self.socket_set.borrow_mut(); + let socket: &mut RawSocket = socket_set.get_mut(handle.socket_handle).as_socket(); + socket.send_slice(buf).expect("Can't send slice"); + Ok(buf.len()) + } + + fn read(&mut self, fd: usize, buf: &mut [u8]) -> syscall::Result { + use smoltcp::socket::AsSocket; + + let handle = self.raw_sockets + .get(&fd) + .ok_or_else(|| syscall::Error::new(syscall::EBADF))?; + let mut socket_set = self.socket_set.borrow_mut(); + let socket: &mut RawSocket = socket_set.get_mut(handle.socket_handle).as_socket(); + if socket.can_recv() { + let length = socket.recv_slice(buf).expect("Can't receive slice"); + trace!("IP Read fd {} len {}", fd, length); + Ok(length) + } else if handle.flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK { + Ok(0) + } else { + Err(syscall::Error::new(syscall::EWOULDBLOCK)) + } + } + + fn fevent(&mut self, fd: usize, events: usize) -> syscall::Result { + trace!("IP fevent {}", fd); + let handle = self.raw_sockets + .get_mut(&fd) + .ok_or_else(|| syscall::Error::new(syscall::EBADF))?; + handle.events = events; + Ok(fd) + } + + fn fsync(&mut self, fd: usize) -> syscall::Result { + trace!("IP fsync {}", fd); + { + let _handle = self.raw_sockets + .get_mut(&fd) + .ok_or_else(|| syscall::Error::new(syscall::EBADF))?; + } + Ok(0) + // TODO Implement fsyncing + // self.0.network_fsync() + } +} diff --git a/src/smolnetd/scheme/mod.rs b/src/smolnetd/scheme/mod.rs new file mode 100644 index 0000000000..51a1522355 --- /dev/null +++ b/src/smolnetd/scheme/mod.rs @@ -0,0 +1,205 @@ +use netutils::{getcfg, MacAddr}; +use smoltcp; +use std::cell::RefCell; +use std::collections::VecDeque; +use std::fs::File; +use std::io::{Read, Write}; +use std::mem; +use std::net::Ipv4Addr; +use std::rc::Rc; +use std::str::FromStr; +use std::time::Instant; +use syscall::SchemeMut; +use syscall; + +use buffer_pool::{Buffer, BufferPool}; +use device::NetworkDevice; +use error::{Error, Result}; +use self::ip::IpScheme; +use self::udp::UdpScheme; + +mod ip; +mod udp; + +type SocketSet = Rc>>; + +pub struct Smolnetd { + network_file: Rc>, + ip_file: File, + udp_file: File, + time_file: File, + + iface: smoltcp::iface::EthernetInterface<'static, 'static, 'static, NetworkDevice>, + socket_set: SocketSet, + + startup_time: Instant, + + ip_scheme: IpScheme, + udp_scheme: UdpScheme, + + input_queue: Rc>>, + input_buffer_pool: BufferPool, +} + +impl Smolnetd { + const INGRESS_PACKET_SIZE: usize = 2048; + const SOCKET_BUFFER_SIZE: usize = 128; //packets + const CHECK_TIMEOUT_MS: i64 = 1000; + + pub fn new(network_file: File, ip_file: File, udp_file: File, time_file: File) -> Smolnetd { + let arp_cache = smoltcp::iface::SliceArpCache::new(vec![Default::default(); 8]); + //TODO Use smoltcp::wire::EthernetAddress::from_str + let mac_addr = MacAddr::from_str(&getcfg("mac").unwrap().trim()); + let hardware_addr = smoltcp::wire::EthernetAddress(mac_addr.bytes); + //TODO Use smoltcp::wire::Ipv4Addr::from_str + let ip_bytes = Ipv4Addr::from_str(&getcfg("ip").unwrap().trim()) + .unwrap() + .octets(); + let protocol_addrs = [ + smoltcp::wire::IpAddress::Ipv4(smoltcp::wire::Ipv4Address::from_bytes(&ip_bytes)), + ]; + let default_gw = smoltcp::wire::IpAddress::Ipv4(smoltcp::wire::Ipv4Address::from_bytes( + &Ipv4Addr::from_str(&getcfg("ip_router").unwrap().trim()) + .unwrap() + .octets(), + )); + trace!("mac {:?} ip {:?}", hardware_addr, protocol_addrs); + let input_queue = Rc::new(RefCell::new(VecDeque::new())); + let network_file = Rc::new(RefCell::new(network_file)); + let network_device = NetworkDevice::new(network_file.clone(), input_queue.clone()); + let mut iface = smoltcp::iface::EthernetInterface::new( + Box::new(network_device), + Box::new(arp_cache) as Box, + hardware_addr, + protocol_addrs, + ); + iface.set_default_gateway(24, Some(default_gw)); + let socket_set = Rc::new(RefCell::new(smoltcp::socket::SocketSet::new(vec![]))); + Smolnetd { + iface, + socket_set: socket_set.clone(), + startup_time: Instant::now(), + ip_file, + udp_file, + time_file, + ip_scheme: IpScheme::new(socket_set.clone()), + udp_scheme: UdpScheme::new(socket_set.clone()), + input_queue, + network_file, + input_buffer_pool: BufferPool::new(Self::INGRESS_PACKET_SIZE), + } + } + + pub fn on_network_scheme_event(&mut self) -> Result> { + if self.read_frames()? > 0 { + self.poll().map(Some)?; + } + Ok(None) + } + + pub fn on_ip_scheme_event(&mut self) -> Result> { + loop { + let mut packet = syscall::Packet::default(); + if self.ip_file.read(&mut packet)? == 0 { + break; + } + self.ip_scheme.handle(&mut packet); + self.ip_file.write_all(&packet)?; + } + Ok(None) + } + + pub fn on_udp_scheme_event(&mut self) -> Result> { + loop { + let mut packet = syscall::Packet::default(); + if self.udp_file.read(&mut packet)? == 0 { + break; + } + self.udp_scheme.handle(&mut packet); + self.udp_file.write_all(&packet)?; + } + Ok(None) + } + + pub fn on_time_event(&mut self) -> Result> { + let mut time = syscall::data::TimeSpec::default(); + if self.time_file.read(&mut time)? < mem::size_of::() { + panic!(); + } + let mut time_ms = time.tv_sec * 1000i64 + (time.tv_nsec as i64) / 1_000_000i64; + time_ms += Smolnetd::CHECK_TIMEOUT_MS; + time.tv_sec = time_ms / 1000; + time.tv_nsec = ((time_ms % 1000) * 1_000_00) as i32; + self.time_file + .write_all(&time) + .map_err(|e| Error::from_io_error(e, "Failed to write to time file"))?; + + self.poll().map(Some)?; + Ok(None) + } + + fn poll(&mut self) -> Result<()> { + let timestamp = self.get_timestamp(); + self.iface + .poll(&mut *self.socket_set.borrow_mut(), timestamp) + .expect("poll error"); + self.notify_raw_sockets() + } + + fn read_frames(&mut self) -> Result { + let mut total_frames = 0; + loop { + let mut buffer = self.input_buffer_pool.get_buffer(); + let count = self.network_file + .borrow_mut() + .read(&mut buffer) + .map_err(|e| { + Error::from_io_error(e, "Failed to read from network file") + })?; + if count == 0 { + break; + } + trace!("got frame {}", count); + buffer.resize(count); + self.input_queue.borrow_mut().push_back(buffer); + total_frames += 1; + } + Ok(total_frames) + } + + fn get_timestamp(&self) -> u64 { + let duration = Instant::now().duration_since(self.startup_time); + let duration_ms = (duration.as_secs() * 1000) + (duration.subsec_nanos() / 1000000) as u64; + duration_ms + } + + fn network_fsync(&mut self) -> syscall::Result { + use std::os::unix::io::AsRawFd; + syscall::fsync(self.network_file.borrow_mut().as_raw_fd() as usize) + } + + fn notify_raw_sockets(&mut self) -> Result<()> { + let ip_file = &mut self.ip_file; + self.ip_scheme + .notify_ready_sockets(|fd| post_fevent(ip_file, fd, syscall::EVENT_READ, 1))?; + let udp_file = &mut self.udp_file; + self.udp_scheme + .notify_ready_sockets(|fd| post_fevent(udp_file, fd, syscall::EVENT_READ, 1)) + } +} + +fn post_fevent(scheme_file: &mut File, fd: usize, event: usize, data_len: usize) -> Result<()> { + scheme_file + .write(&syscall::Packet { + id: 0, + pid: 0, + uid: 0, + gid: 0, + a: syscall::number::SYS_FEVENT, + b: fd, + c: event, + d: data_len, + }) + .map(|_| ()) + .map_err(|e| Error::from_io_error(e, "failed to post fevent")) +} diff --git a/src/smolnetd/scheme/udp.rs b/src/smolnetd/scheme/udp.rs new file mode 100644 index 0000000000..0d538f94d6 --- /dev/null +++ b/src/smolnetd/scheme/udp.rs @@ -0,0 +1,171 @@ +use netutils::Ipv4Addr; +use smoltcp::socket::{AsSocket, SocketHandle, UdpPacketBuffer, UdpSocket, UdpSocketBuffer}; +use smoltcp::wire::{IpAddress, IpEndpoint, Ipv4Address}; +use std::collections::BTreeMap; +use syscall; + +use device::NetworkDevice; +use error::Result; +use super::{Smolnetd, SocketSet}; + +pub struct UdpHandle { + flags: usize, + events: usize, + remote_endpoint: IpEndpoint, + pub socket_handle: SocketHandle, +} + +pub struct UdpScheme { + next_udp_fd: usize, + udp_sockets: BTreeMap, + socket_set: SocketSet, +} + +impl UdpScheme { + pub fn new(socket_set: SocketSet) -> UdpScheme { + UdpScheme { + next_udp_fd: 1, + udp_sockets: BTreeMap::new(), + socket_set, + } + } + + pub fn notify_ready_sockets Result<()>>(&self, mut f: F) -> Result<()> { + for (&fd, ref handle) in &self.udp_sockets { + let mut socket_set = self.socket_set.borrow_mut(); + let socket: &mut UdpSocket = socket_set.get_mut(handle.socket_handle).as_socket(); + if socket.can_send() { + f(fd)? + } + } + Ok(()) + } +} + +impl syscall::SchemeMut for UdpScheme { + fn open(&mut self, url: &[u8], flags: usize, _uid: u32, _gid: u32) -> syscall::Result { + use std::str; + + let path = str::from_utf8(url).or_else(|_| Err(syscall::Error::new(syscall::EINVAL)))?; + trace!("Udp open {} ", path); + let mut parts = path.split("/"); + let (remote_ip, remote_port) = parse_socket(parts.next().unwrap_or("")); + let (local_ip, local_port) = parse_socket(parts.next().unwrap_or("")); + + let mut rx_packets = Vec::with_capacity(Smolnetd::SOCKET_BUFFER_SIZE); + let mut tx_packets = Vec::with_capacity(Smolnetd::SOCKET_BUFFER_SIZE); + for _ in 0..Smolnetd::SOCKET_BUFFER_SIZE { + rx_packets.push(UdpPacketBuffer::new(vec![0; NetworkDevice::MTU])); + tx_packets.push(UdpPacketBuffer::new(vec![0; NetworkDevice::MTU])); + } + let rx_buffer = UdpSocketBuffer::new(rx_packets); + let tx_buffer = UdpSocketBuffer::new(tx_packets); + let mut udp_socket = UdpSocket::new(rx_buffer, tx_buffer); + + if local_ip != Ipv4Addr::NULL && local_port != 0 { + let udp_socket: &mut UdpSocket = udp_socket.as_socket(); + udp_socket + .bind(IpEndpoint::new( + IpAddress::Ipv4(Ipv4Address::from_bytes(&local_ip.bytes)), + local_port, + )) + .unwrap(); + } + + let socket_handle = self.socket_set.borrow_mut().add(udp_socket); + let id = self.next_udp_fd; + + self.udp_sockets.insert( + id, + UdpHandle { + flags, + events: 0, + socket_handle, + remote_endpoint: IpEndpoint::new( + IpAddress::Ipv4(Ipv4Address::from_bytes(&remote_ip.bytes)), + remote_port, + ), + }, + ); + self.next_udp_fd += 1; + trace!("Udp open fd {} ", id); + Ok(id) + } + + fn close(&mut self, fd: usize) -> syscall::Result { + trace!("Upd close {}", fd); + let socket_handle = { + let handle = self.udp_sockets + .get(&fd) + .ok_or_else(|| syscall::Error::new(syscall::EBADF))?; + handle.socket_handle + }; + self.udp_sockets.remove(&fd); + self.socket_set.borrow_mut().remove(socket_handle); + Ok(0) + } + + fn write(&mut self, fd: usize, buf: &[u8]) -> syscall::Result { + trace!("Upd write {} len {}", fd, buf.len()); + + let handle = self.udp_sockets + .get(&fd) + .ok_or_else(|| syscall::Error::new(syscall::EBADF))?; + let mut socket_set = self.socket_set.borrow_mut(); + let socket: &mut UdpSocket = socket_set.get_mut(handle.socket_handle).as_socket(); + socket + .send_slice(buf, handle.remote_endpoint) + .expect("Can't send slice"); + Ok(buf.len()) + } + + fn read(&mut self, fd: usize, buf: &mut [u8]) -> syscall::Result { + let handle = self.udp_sockets.get(&fd).ok_or_else(|| { + trace!("UDP read EBADF {}", fd); + syscall::Error::new(syscall::EBADF) + })?; + let mut socket_set = self.socket_set.borrow_mut(); + let socket: &mut UdpSocket = socket_set.get_mut(handle.socket_handle).as_socket(); + if socket.can_recv() { + let (length, _) = socket.recv_slice(buf).expect("Can't receive slice"); + trace!("Upd read {}", fd); + Ok(length) + } else if handle.flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK { + Ok(0) + } else { + Err(syscall::Error::new(syscall::EWOULDBLOCK)) + } + } + + fn fevent(&mut self, fd: usize, events: usize) -> syscall::Result { + trace!("udp fevent {}", fd); + let handle = self.udp_sockets + .get_mut(&fd) + .ok_or_else(|| syscall::Error::new(syscall::EBADF))?; + handle.events = events; + Ok(fd) + } + + fn fsync(&mut self, fd: usize) -> syscall::Result { + trace!("udp fsync {}", fd); + { + let _handle = self.udp_sockets + .get_mut(&fd) + .ok_or_else(|| syscall::Error::new(syscall::EBADF))?; + } + Ok(0) + // TODO Implement fsyncing + // self.0.network_fsync() + } +} + +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) +}