From 3198a8eb6942f244055c8240962aaafc9e4b60f7 Mon Sep 17 00:00:00 2001 From: Egor Karavaev Date: Tue, 26 Sep 2017 23:51:04 +0300 Subject: [PATCH] UDP settings. --- src/smolnetd/buffer_pool.rs | 2 +- src/smolnetd/device.rs | 2 +- src/smolnetd/main.rs | 18 +-- src/smolnetd/port_set.rs | 2 +- src/smolnetd/scheme/ip.rs | 5 +- src/smolnetd/scheme/mod.rs | 24 ++-- src/smolnetd/scheme/udp.rs | 217 +++++++++++++++++++++++++++--------- 7 files changed, 192 insertions(+), 78 deletions(-) diff --git a/src/smolnetd/buffer_pool.rs b/src/smolnetd/buffer_pool.rs index 2bd2e475c5..f336266778 100644 --- a/src/smolnetd/buffer_pool.rs +++ b/src/smolnetd/buffer_pool.rs @@ -86,7 +86,7 @@ impl BufferPool { Buffer { buffer, - stack: self.stack.clone(), + stack: Rc::clone(&self.stack), } } } diff --git a/src/smolnetd/device.rs b/src/smolnetd/device.rs index 37cbb9d5c0..74f0785cd6 100644 --- a/src/smolnetd/device.rs +++ b/src/smolnetd/device.rs @@ -69,7 +69,7 @@ impl smoltcp::phy::Device for NetworkDevice { fn transmit(&mut self, _timestamp: u64, length: usize) -> smoltcp::Result { Ok(TxBuffer { - network_file: self.network_file.clone(), + network_file: Rc::clone(&self.network_file), buffer: vec![0; length], }) } diff --git a/src/smolnetd/main.rs b/src/smolnetd/main.rs index d161688c2b..65fd372f88 100644 --- a/src/smolnetd/main.rs +++ b/src/smolnetd/main.rs @@ -33,8 +33,8 @@ fn run() -> Result<()> { trace!("opening network:"); let network_fd = syscall::open("network:", O_RDWR | O_NONBLOCK) - .map_err(|e| Error::from_syscall_error(e, "failed to open network:"))? as - RawFd; + .map_err(|e| Error::from_syscall_error(e, "failed to open network:"))? + as RawFd; trace!("opening :ip"); let ip_fd = syscall::open(":ip", O_RDWR | O_CREAT | O_NONBLOCK) @@ -42,13 +42,13 @@ fn run() -> Result<()> { trace!("opening :udp"); let udp_fd = syscall::open(":udp", O_RDWR | O_CREAT | O_NONBLOCK) - .map_err(|e| Error::from_syscall_error(e, "failed to open :udp"))? as - RawFd; + .map_err(|e| Error::from_syscall_error(e, "failed to open :udp"))? + as RawFd; let time_path = format!("time:{}", syscall::CLOCK_MONOTONIC); let time_fd = syscall::open(&time_path, syscall::O_RDWR) - .map_err(|e| Error::from_syscall_error(e, "failed to open time:"))? as - RawFd; + .map_err(|e| Error::from_syscall_error(e, "failed to open time:"))? + as RawFd; let (network_file, ip_file, time_file, udp_file) = unsafe { ( @@ -66,7 +66,7 @@ fn run() -> Result<()> { let mut event_queue = EventQueue::<(), Error>::new() .map_err(|e| Error::from_io_error(e, "failed to create event queue"))?; - let smolnetd_ = smolnetd.clone(); + let smolnetd_ = Rc::clone(&smolnetd); event_queue .add(network_fd, move |_| { @@ -76,13 +76,13 @@ fn run() -> Result<()> { Error::from_io_error(e, "failed to listen to network events") })?; - let smolnetd_ = smolnetd.clone(); + let smolnetd_ = Rc::clone(&smolnetd); event_queue .add(ip_fd, move |_| smolnetd_.borrow_mut().on_ip_scheme_event()) .map_err(|e| Error::from_io_error(e, "failed to listen to ip events"))?; - let smolnetd_ = smolnetd.clone(); + let smolnetd_ = Rc::clone(&smolnetd); event_queue .add( diff --git a/src/smolnetd/port_set.rs b/src/smolnetd/port_set.rs index 66d42244b9..88011ec337 100644 --- a/src/smolnetd/port_set.rs +++ b/src/smolnetd/port_set.rs @@ -35,7 +35,7 @@ impl PortSet { self.next = self.next.wrapping_add(1); }; - return Some(port); + Some(port) } pub fn claim_port(&mut self, port: u16) -> bool { diff --git a/src/smolnetd/scheme/ip.rs b/src/smolnetd/scheme/ip.rs index f454b555be..4b2a4932fa 100644 --- a/src/smolnetd/scheme/ip.rs +++ b/src/smolnetd/scheme/ip.rs @@ -47,7 +47,7 @@ impl IpScheme { } pub fn notify_sockets(&mut self) -> Result<()> { - for (&fd, ref handle) in &self.raw_sockets { + for (&fd, 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() { @@ -66,7 +66,8 @@ impl<'a> syscall::SchemeMut for IpScheme { 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 proto = + u8::from_str_radix(path, 16).or_else(|_| 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); diff --git a/src/smolnetd/scheme/mod.rs b/src/smolnetd/scheme/mod.rs index fcc36778b8..ed4758bc36 100644 --- a/src/smolnetd/scheme/mod.rs +++ b/src/smolnetd/scheme/mod.rs @@ -44,18 +44,17 @@ impl Smolnetd { 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]); - let hardware_addr = smoltcp::wire::EthernetAddress::from_str( - &getcfg("mac").unwrap().trim(), - ).expect("Can't parse the 'mac' cfg"); - let local_ip = smoltcp::wire::IpAddress::from_str(&getcfg("ip").unwrap().trim()) + let hardware_addr = smoltcp::wire::EthernetAddress::from_str(getcfg("mac").unwrap().trim()) + .expect("Can't parse the 'mac' cfg"); + let local_ip = smoltcp::wire::IpAddress::from_str(getcfg("ip").unwrap().trim()) .expect("Can't parse the 'ip' cfg."); let protocol_addrs = [smoltcp::wire::IpCidr::new(local_ip, 24).unwrap()]; - let default_gw = smoltcp::wire::IpAddress::from_str(&getcfg("ip_router").unwrap().trim()) + let default_gw = smoltcp::wire::IpAddress::from_str(getcfg("ip_router").unwrap().trim()) .expect("Can't parse the 'ip_router' cfg."); // 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 network_device = NetworkDevice::new(Rc::clone(&network_file), Rc::clone(&input_queue)); let iface = smoltcp::iface::EthernetInterface::new( Box::new(network_device), Box::new(arp_cache) as Box, @@ -66,11 +65,11 @@ impl Smolnetd { let socket_set = Rc::new(RefCell::new(smoltcp::socket::SocketSet::new(vec![]))); Smolnetd { iface, - socket_set: socket_set.clone(), + socket_set: Rc::clone(&socket_set), startup_time: Instant::now(), time_file, - ip_scheme: IpScheme::new(socket_set.clone(), ip_file), - udp_scheme: UdpScheme::new(socket_set.clone(), udp_file), + ip_scheme: IpScheme::new(Rc::clone(&socket_set), ip_file), + udp_scheme: UdpScheme::new(Rc::clone(&socket_set), udp_file), input_queue, network_file, input_buffer_pool: BufferPool::new(Self::INGRESS_PACKET_SIZE), @@ -97,10 +96,10 @@ impl Smolnetd { 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; + let mut time_ms = time.tv_sec * 1000i64 + i64::from(time.tv_nsec) / 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; + time.tv_nsec = ((time_ms % 1000) * 1_000_000) as i32; self.time_file .write_all(&time) .map_err(|e| Error::from_io_error(e, "Failed to write to time file"))?; @@ -140,8 +139,7 @@ impl Smolnetd { 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 + (duration.as_secs() * 1000) + u64::from(duration.subsec_nanos() / 1_000_000) } fn network_fsync(&mut self) -> syscall::Result { diff --git a/src/smolnetd/scheme/udp.rs b/src/smolnetd/scheme/udp.rs index a1a7eed66e..59cbbbe725 100644 --- a/src/smolnetd/scheme/udp.rs +++ b/src/smolnetd/scheme/udp.rs @@ -5,7 +5,11 @@ use std::fs::File; use std::io::{Read, Write}; use std::str::FromStr; use std::str; +use std::mem; +use std::ops::Deref; +use std::ops::DerefMut; use syscall::SchemeMut; +use syscall::data::TimeSpec; use syscall; use device::NetworkDevice; @@ -14,6 +18,7 @@ use super::{Smolnetd, SocketSet}; use port_set::PortSet; use super::post_fevent; +#[derive(Copy, Clone, Eq, PartialEq)] enum Setting { Ttl, ReadTimeout, @@ -24,19 +29,27 @@ struct UdpHandle { flags: usize, events: usize, remote_endpoint: IpEndpoint, + read_timeout: Option, + write_timeout: Option, socket_handle: SocketHandle, } +struct SettingHandle { + fd: usize, + socket_handle: SocketHandle, + setting: Setting, +} + enum FdHandle { - Setting(SocketHandle, Setting), + Setting(SettingHandle), Socket(UdpHandle), } impl FdHandle { fn socket_handle(&self) -> SocketHandle { match *self { - FdHandle::Socket(UdpHandle { socket_handle, .. }) => socket_handle, - FdHandle::Setting(socket_handle, _) => socket_handle, + FdHandle::Socket(UdpHandle { socket_handle, .. }) | + FdHandle::Setting(SettingHandle { socket_handle, .. }) => socket_handle, } } } @@ -56,7 +69,7 @@ impl UdpScheme { udp_fds: BTreeMap::new(), socket_set, // 49152..65535 is the suggested range for dynamic private ports - port_set: PortSet::new(49152u16, 65535u16).expect("Wrong UDP port numbers"), + port_set: PortSet::new(49_152u16, 65_535u16).expect("Wrong UDP port numbers"), udp_file, } } @@ -75,7 +88,7 @@ impl UdpScheme { pub fn notify_sockets(&mut self) -> Result<()> { for (&fd, handle) in &self.udp_fds { - if let &FdHandle::Socket(UdpHandle { socket_handle, .. }) = handle { + if let FdHandle::Socket(UdpHandle { socket_handle, .. }) = *handle { let mut socket_set = self.socket_set.borrow_mut(); let socket: &mut UdpSocket = socket_set.get_mut(socket_handle).as_socket(); if socket.can_send() { @@ -85,6 +98,83 @@ impl UdpScheme { } Ok(()) } + + fn get_setting( + &mut self, + fd: usize, + setting: Setting, + buf: &mut [u8], + ) -> syscall::Result { + let handle = self.udp_fds + .get_mut(&fd) + .ok_or_else(|| syscall::Error::new(syscall::EBADF))?; + let handle = match *handle { + FdHandle::Socket(ref mut handle) => handle, + _ => { + return Err(syscall::Error::new(syscall::EBADF)); + } + }; + let timespec = match (setting, handle.read_timeout, handle.write_timeout) { + (Setting::ReadTimeout, Some(read_timeout), _) => read_timeout, + (Setting::WriteTimeout, _, Some(write_timeout)) => write_timeout, + _ => { + return Ok(0); + } + }; + + if buf.len() < mem::size_of::() { + Ok(0) + } else { + let count = timespec.deref().read(buf).map_err(|err| { + syscall::Error::new(err.raw_os_error().unwrap_or(syscall::EIO)) + })?; + Ok(count) + } + } + + fn update_setting( + &mut self, + fd: usize, + setting: Setting, + buf: &[u8], + ) -> syscall::Result { + let handle = self.udp_fds + .get_mut(&fd) + .ok_or_else(|| syscall::Error::new(syscall::EBADF))?; + let handle = match *handle { + FdHandle::Socket(ref mut handle) => handle, + _ => { + return Err(syscall::Error::new(syscall::EBADF)); + } + }; + match setting { + Setting::ReadTimeout | Setting::WriteTimeout => { + let (timeout, count) = { + if buf.len() < mem::size_of::() { + (None, 0) + } else { + let mut timespec = TimeSpec::default(); + let count = timespec.deref_mut().write(buf).map_err(|err| { + syscall::Error::new(err.raw_os_error().unwrap_or(syscall::EIO)) + })?; + (Some(timespec), count) + } + }; + match setting { + Setting::ReadTimeout => { + handle.read_timeout = timeout; + } + Setting::WriteTimeout => { + handle.write_timeout = timeout; + } + _ => {} + }; + return Ok(count); + } + Setting::Ttl => {} + } + Ok(0) + } } impl syscall::SchemeMut for UdpScheme { @@ -93,7 +183,7 @@ impl syscall::SchemeMut for UdpScheme { trace!("Udp open {} ", path); - let mut parts = path.split("/"); + let mut parts = path.split('/'); let remote_endpoint = parse_endpoint(parts.next().unwrap_or("")); let mut local_endpoint = parse_endpoint(parts.next().unwrap_or("")); @@ -135,6 +225,8 @@ impl syscall::SchemeMut for UdpScheme { flags, events: 0, socket_handle, + write_timeout: None, + read_timeout: None, remote_endpoint: remote_endpoint, }), ); @@ -169,53 +261,60 @@ impl syscall::SchemeMut for UdpScheme { fn write(&mut self, fd: usize, buf: &[u8]) -> syscall::Result { trace!("Upd write {} len {}", fd, buf.len()); - let handle = self.udp_fds - .get(&fd) - .ok_or_else(|| syscall::Error::new(syscall::EBADF))?; - match *handle { - FdHandle::Setting(_, _) => { - //TODO: udp settings - // pretend we've accepted - } - FdHandle::Socket(ref handle) => { - if !handle.remote_endpoint.is_specified() { - return Err(syscall::Error::new(syscall::EADDRNOTAVAIL)); + let (fd, setting) = { + let handle = self.udp_fds + .get(&fd) + .ok_or_else(|| syscall::Error::new(syscall::EBADF))?; + + match *handle { + FdHandle::Setting(ref setting_handle) => { + (setting_handle.fd, setting_handle.setting) + } + FdHandle::Socket(ref handle) => { + if !handle.remote_endpoint.is_specified() { + return Err(syscall::Error::new(syscall::EADDRNOTAVAIL)); + } + 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"); + return Ok(buf.len()); } - 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()) + }; + self.update_setting(fd, setting, buf) } fn read(&mut self, fd: usize, buf: &mut [u8]) -> syscall::Result { trace!("udp read {} {}", fd, buf.len()); - let handle = self.udp_fds.get(&fd).ok_or_else(|| { - trace!("UDP read EBADF {}", fd); - syscall::Error::new(syscall::EBADF) - })?; - match *handle { - FdHandle::Setting(_, _) => { - //TODO: udp settings - Ok(buf.len()) - } - FdHandle::Socket(ref handle) => { - 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)) + let (fd, setting) = { + let handle = self.udp_fds.get(&fd).ok_or_else(|| { + trace!("UDP read EBADF {}", fd); + syscall::Error::new(syscall::EBADF) + })?; + match *handle { + FdHandle::Setting(ref setting_handle) => { + (setting_handle.fd, setting_handle.setting) + } + FdHandle::Socket(ref handle) => { + let mut socket_set = self.socket_set.borrow_mut(); + let socket: &mut UdpSocket = + socket_set.get_mut(handle.socket_handle).as_socket(); + return 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)) + }; } } - } + }; + self.get_setting(fd, setting, buf) } fn dup(&mut self, fd: usize, buf: &[u8]) -> syscall::Result { @@ -230,15 +329,29 @@ impl syscall::SchemeMut for UdpScheme { let socket_handle = handle.socket_handle(); match path { - "ttl" => FdHandle::Setting(socket_handle, Setting::Ttl), - "read_timeout" => FdHandle::Setting(socket_handle, Setting::ReadTimeout), - "write_timeout" => FdHandle::Setting(socket_handle, Setting::WriteTimeout), + "ttl" => FdHandle::Setting(SettingHandle { + socket_handle, + fd, + setting: Setting::Ttl, + }), + "read_timeout" => FdHandle::Setting(SettingHandle { + socket_handle, + fd, + setting: Setting::ReadTimeout, + }), + "write_timeout" => FdHandle::Setting(SettingHandle { + socket_handle, + fd, + setting: Setting::WriteTimeout, + }), _ => { let remote_endpoint = parse_endpoint(path); - if let &mut FdHandle::Socket(ref udp_handle) = handle { + if let FdHandle::Socket(ref udp_handle) = *handle { FdHandle::Socket(UdpHandle { flags: udp_handle.flags, events: udp_handle.events, + read_timeout: udp_handle.read_timeout, + write_timeout: udp_handle.write_timeout, remote_endpoint: if remote_endpoint.is_specified() { remote_endpoint } else { @@ -250,6 +363,8 @@ impl syscall::SchemeMut for UdpScheme { FdHandle::Socket(UdpHandle { flags: 0, events: 0, + read_timeout: None, + write_timeout: None, remote_endpoint: remote_endpoint, socket_handle, }) @@ -279,7 +394,7 @@ impl syscall::SchemeMut for UdpScheme { .get_mut(&fd) .ok_or_else(|| syscall::Error::new(syscall::EBADF))?; match *handle { - FdHandle::Setting(_, _) => Err(syscall::Error::new(syscall::EBADF)), + FdHandle::Setting(_) => Err(syscall::Error::new(syscall::EBADF)), FdHandle::Socket(ref mut handle) => { handle.events = events; Ok(fd) @@ -301,7 +416,7 @@ impl syscall::SchemeMut for UdpScheme { } fn parse_endpoint(socket: &str) -> IpEndpoint { - let mut socket_parts = socket.split(":"); + let mut socket_parts = socket.split(':'); let host = IpAddress::Ipv4( Ipv4Address::from_str(socket_parts.next().unwrap_or("")) .unwrap_or_else(|_| Ipv4Address::new(0, 0, 0, 0)),