use std::cell::RefCell; use std::collections::BTreeMap; use std::fs::File; use std::io::{ErrorKind, Read, Write}; use std::marker::PhantomData; use std::mem; use std::ops::Deref; use std::ops::DerefMut; use std::rc::Rc; use std::str; use syscall; use syscall::{Error as SyscallError, EventFlags as SyscallEventFlags, Packet as SyscallPacket, Result as SyscallResult, SchemeBlockMut}; use syscall::data::TimeSpec; use syscall::flag::{EVENT_READ, EVENT_WRITE}; use redox_netstack::error::{Error, Result}; use smoltcp::socket::{AnySocket, SocketHandle}; use super::{post_fevent, SocketSet}; pub struct NullFile { pub flags: usize, pub uid: u32, pub gid: u32, } pub struct SocketFile { pub flags: usize, pub data: DataT, events: usize, socket_handle: SocketHandle, read_notified: bool, write_notified: bool, read_timeout: Option, write_timeout: Option, } impl SocketFile { pub fn clone_with_data(&self, data: DataT) -> SocketFile { SocketFile { flags: self.flags, events: self.events, read_notified: false, // we still want to notify about this new socket write_notified: false, read_timeout: self.read_timeout, write_timeout: self.write_timeout, socket_handle: self.socket_handle, data, } } pub fn new_with_data(socket_handle: SocketHandle, data: DataT) -> SocketFile { SocketFile { flags: 0, events: 0, read_notified: false, write_notified: false, read_timeout: None, write_timeout: None, socket_handle, data, } } } #[derive(Copy, Clone)] enum Setting { Ttl, ReadTimeout, WriteTimeout, #[allow(dead_code)] Other(SettingT), } pub struct SettingFile { fd: usize, socket_handle: SocketHandle, setting: Setting, } pub enum SchemeFile where SocketT: SchemeSocket, { Setting(SettingFile), Socket(SocketFile), } impl SchemeFile where SocketT: SchemeSocket, { pub fn socket_handle(&self) -> SocketHandle { match *self { SchemeFile::Socket(SocketFile { socket_handle, .. }) | SchemeFile::Setting(SettingFile { socket_handle, .. }) => socket_handle, } } pub fn events(&mut self, socket_set: &mut SocketSet) -> usize where SocketT: AnySocket<'static, 'static> { let mut revents = 0; if let &mut SchemeFile::Socket(SocketFile { socket_handle, events, ref mut read_notified, ref mut write_notified, .. }) = self { let socket = socket_set.get::(socket_handle); if events & syscall::EVENT_READ.bits() == syscall::EVENT_READ.bits() && (socket.can_recv() || !socket.may_recv()) { if !*read_notified { *read_notified = true; revents |= EVENT_READ.bits(); } } else { *read_notified = false; } if events & syscall::EVENT_WRITE.bits() == syscall::EVENT_WRITE.bits() && socket.can_send() { if !*write_notified { *write_notified = true; revents |= EVENT_WRITE.bits(); } } else { *write_notified = false; } } revents } } #[derive(Default, Clone)] struct WaitHandle { until: Option, packet: SyscallPacket, } type WaitQueue = Vec; pub type DupResult = Option<( SchemeFile, Option<(SocketHandle, ::DataT)>, )>; pub trait SchemeSocket where Self: ::std::marker::Sized, { type SchemeDataT; type DataT; type SettingT: Copy; fn new_scheme_data() -> Self::SchemeDataT; fn can_send(&self) -> bool; fn can_recv(&self) -> bool; fn may_recv(&self) -> bool; fn hop_limit(&self) -> u8; fn set_hop_limit(&mut self, u8); fn get_setting(&SocketFile, Self::SettingT, &mut [u8]) -> SyscallResult; fn set_setting(&mut SocketFile, Self::SettingT, &[u8]) -> SyscallResult; fn new_socket( &mut SocketSet, &str, u32, &mut Self::SchemeDataT, ) -> SyscallResult<(SocketHandle, Self::DataT)>; fn close_file(&self, &SchemeFile, &mut Self::SchemeDataT) -> SyscallResult<()>; fn write_buf(&mut self, &mut SocketFile, buf: &[u8]) -> SyscallResult>; fn read_buf(&mut self, &mut SocketFile, buf: &mut [u8]) -> SyscallResult>; fn fpath(&self, &SchemeFile, &mut [u8]) -> SyscallResult; fn dup( &mut SocketSet, &mut SchemeFile, &str, &mut Self::SchemeDataT, ) -> SyscallResult>; } pub struct SocketScheme where SocketT: SchemeSocket + AnySocket<'static, 'static>, { next_fd: usize, nulls: BTreeMap, files: BTreeMap>, socket_set: Rc>, scheme_file: File, wait_queue: WaitQueue, scheme_data: SocketT::SchemeDataT, _phantom_socket: PhantomData, } impl SocketScheme where SocketT: SchemeSocket + AnySocket<'static, 'static>, { pub fn new(socket_set: Rc>, scheme_file: File) -> SocketScheme { SocketScheme { next_fd: 1, nulls: BTreeMap::new(), files: BTreeMap::new(), socket_set, scheme_data: SocketT::new_scheme_data(), scheme_file, wait_queue: Vec::new(), _phantom_socket: PhantomData, } } pub fn on_scheme_event(&mut self) -> Result> { let result = loop { let mut packet = SyscallPacket::default(); match self.scheme_file.read(&mut packet) { Ok(0) => { //TODO: Cleanup must occur break Some(()); }, Ok(_) => (), Err(err) => if err.kind() == ErrorKind::WouldBlock { break None; } else { return Err(Error::from(err)); } } if let Some(a) = self.handle(&mut packet) { packet.a = a; self.scheme_file.write_all(&packet)?; } else { match self.handle_block(&mut packet) { Ok(timeout) => { self.wait_queue.push(WaitHandle { until: timeout, packet: packet, }); }, Err(err) => { packet.a = (-err.errno) as usize; self.scheme_file.write_all(&packet)?; return Err(Error::from_syscall_error( err, "Can't handle blocked socket", )); } } } }; Ok(result) } pub fn notify_sockets(&mut self) -> Result<()> { let mut cur_time = TimeSpec::default(); syscall::clock_gettime(syscall::CLOCK_MONOTONIC, &mut cur_time) .map_err(|e| Error::from_syscall_error(e, "Can't get time"))?; // Notify non-blocking sockets for (&fd, ref mut file) in &mut self.files { let events = { let mut socket_set = self.socket_set.borrow_mut(); file.events(&mut socket_set) }; if events > 0 { post_fevent(&mut self.scheme_file, fd, events, 1)?; } } // Wake up blocking queue let mut i = 0; while i < self.wait_queue.len() { let mut packet = self.wait_queue[i].packet; if let Some(a) = self.handle(&packet) { self.wait_queue.remove(i); packet.a = a; self.scheme_file.write_all(&packet)?; } else { match self.wait_queue[i].until { Some(until) if (until.tv_sec < cur_time.tv_sec || (until.tv_sec == cur_time.tv_sec && until.tv_nsec < cur_time.tv_nsec)) => { self.wait_queue.remove(i); packet.a = (-syscall::ETIMEDOUT) as usize; self.scheme_file.write_all(&packet)?; }, _ => { i += 1; } } } } Ok(()) } fn handle_block(&mut self, packet: &mut SyscallPacket) -> SyscallResult> { let fd = packet.b; let (read_timeout, write_timeout) = { let file = self.files .get(&fd) .ok_or_else(|| SyscallError::new(syscall::EBADF))?; if let SchemeFile::Socket(ref scheme_file) = *file { Ok(( scheme_file.read_timeout, scheme_file.write_timeout, )) } else { Err(SyscallError::new(syscall::EBADF)) } }?; let mut timeout = match packet.a { syscall::SYS_WRITE => Ok(write_timeout), syscall::SYS_READ => Ok(read_timeout), _ => Ok(None), }?; if let Some(ref mut timeout) = timeout { let mut cur_time = TimeSpec::default(); syscall::clock_gettime(syscall::CLOCK_MONOTONIC, &mut cur_time)?; *timeout = add_time(timeout, &cur_time) } Ok(timeout) } fn get_setting( &mut self, fd: usize, setting: Setting, buf: &mut [u8], ) -> SyscallResult { let file = self.files .get_mut(&fd) .ok_or_else(|| SyscallError::new(syscall::EBADF))?; let file = match *file { SchemeFile::Socket(ref mut file) => file, _ => { return Err(SyscallError::new(syscall::EBADF)); } }; match setting { Setting::Other(setting) => SocketT::get_setting(file, setting, buf), Setting::Ttl => if let Some(hop_limit) = buf.get_mut(0) { let mut socket_set = self.socket_set.borrow_mut(); let socket = socket_set.get::(file.socket_handle); *hop_limit = socket.hop_limit(); Ok(1) } else { Err(SyscallError::new(syscall::EIO)) }, Setting::ReadTimeout | Setting::WriteTimeout => { let timespec = match (setting, file.read_timeout, file.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| { SyscallError::new(err.raw_os_error().unwrap_or(syscall::EIO)) })?; Ok(count) } } } } fn update_setting( &mut self, fd: usize, setting: Setting, buf: &[u8], ) -> SyscallResult { let file = self.files .get_mut(&fd) .ok_or_else(|| SyscallError::new(syscall::EBADF))?; let file = match *file { SchemeFile::Socket(ref mut file) => file, _ => { return Err(SyscallError::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| { SyscallError::new(err.raw_os_error().unwrap_or(syscall::EIO)) })?; (Some(timespec), count) } }; match setting { Setting::ReadTimeout => { file.read_timeout = timeout; } Setting::WriteTimeout => { file.write_timeout = timeout; } _ => {} }; Ok(count) } Setting::Ttl => if let Some(hop_limit) = buf.get(0) { let mut socket_set = self.socket_set.borrow_mut(); let mut socket = socket_set.get::(file.socket_handle); socket.set_hop_limit(*hop_limit); Ok(1) } else { Err(SyscallError::new(syscall::EIO)) }, Setting::Other(setting) => SocketT::set_setting(file, setting, buf), } } } impl syscall::SchemeBlockMut for SocketScheme where SocketT: SchemeSocket + AnySocket<'static, 'static>, { fn open(&mut self, path: &str, flags: usize, uid: u32, _gid: u32) -> SyscallResult> { if path.is_empty() { let null = NullFile { flags: flags, uid: uid, gid: _gid, }; let id = self.next_fd; self.next_fd += 1; self.nulls.insert(id, null); Ok(Some(id)) } else { let (socket_handle, data) = SocketT::new_socket( &mut self.socket_set.borrow_mut(), path, uid, &mut self.scheme_data, )?; let file = SchemeFile::Socket(SocketFile { flags, events: 0, socket_handle, read_notified: false, write_notified: false, write_timeout: None, read_timeout: None, data, }); let id = self.next_fd; self.next_fd += 1; self.files.insert(id, file); Ok(Some(id)) } } fn close(&mut self, fd: usize) -> SyscallResult> { if let Some(_null) = self.nulls.remove(&fd) { return Ok(Some(0)); } let socket_handle = { let file = self.files .get(&fd) .ok_or_else(|| SyscallError::new(syscall::EBADF))?; file.socket_handle() }; let scheme_file = self.files.remove(&fd); let mut socket_set = self.socket_set.borrow_mut(); if let Some(scheme_file) = scheme_file { let socket = socket_set.get::(socket_handle); socket.close_file(&scheme_file, &mut self.scheme_data)?; } self.wait_queue.retain( |&WaitHandle { packet: SyscallPacket { a, .. }, .. }| a != fd, ); socket_set.release(socket_handle); //TODO: removing sockets in release should make prune unnecessary socket_set.prune(); Ok(Some(0)) } fn write(&mut self, fd: usize, buf: &[u8]) -> SyscallResult> { let (fd, setting) = { let file = self.files .get_mut(&fd) .ok_or_else(|| SyscallError::new(syscall::EBADF))?; match *file { SchemeFile::Setting(ref setting_handle) => { (setting_handle.fd, setting_handle.setting) } SchemeFile::Socket(ref mut file) => { let mut socket_set = self.socket_set.borrow_mut(); let mut socket = socket_set.get::(file.socket_handle); return SocketT::write_buf(&mut socket, file, buf); } } }; self.update_setting(fd, setting, buf).map(Some) } fn read(&mut self, fd: usize, buf: &mut [u8]) -> SyscallResult> { let (fd, setting) = { let file = self.files .get_mut(&fd) .ok_or_else(|| SyscallError::new(syscall::EBADF))?; match *file { SchemeFile::Setting(ref setting_handle) => { (setting_handle.fd, setting_handle.setting) } SchemeFile::Socket(ref mut file) => { let mut socket_set = self.socket_set.borrow_mut(); let mut socket = socket_set.get::(file.socket_handle); return SocketT::read_buf(&mut socket, file, buf); } } }; self.get_setting(fd, setting, buf).map(Some) } fn dup(&mut self, fd: usize, buf: &[u8]) -> SyscallResult> { let path = str::from_utf8(buf).or_else(|_| Err(SyscallError::new(syscall::EINVAL)))?; if let Some((flags, uid, gid)) = self.nulls .get(&fd) .map(|null| (null.flags, null.uid, null.gid)) { return self.open(path, flags, uid, gid); } let new_file = { let file = self.files .get_mut(&fd) .ok_or_else(|| SyscallError::new(syscall::EBADF))?; let socket_handle = file.socket_handle(); let (new_handle, update_with) = match path { "hop_limit" => ( SchemeFile::Setting(SettingFile { socket_handle, fd, setting: Setting::Ttl, }), None, ), "read_timeout" => ( SchemeFile::Setting(SettingFile { socket_handle, fd, setting: Setting::ReadTimeout, }), None, ), "write_timeout" => ( SchemeFile::Setting(SettingFile { socket_handle, fd, setting: Setting::WriteTimeout, }), None, ), _ => match SocketT::dup( &mut self.socket_set.borrow_mut(), file, path, &mut self.scheme_data, )? { Some(some) => some, None => return Ok(None), }, }; if let Some((socket_handle, data)) = update_with { if let SchemeFile::Socket(ref mut file) = *file { file.socket_handle = socket_handle; file.data = data; } else { self.socket_set.borrow_mut().retain(file.socket_handle()); } } else { self.socket_set.borrow_mut().retain(file.socket_handle()); } new_handle }; let id = self.next_fd; self.files.insert(id, new_file); self.next_fd += 1; Ok(Some(id)) } fn fevent(&mut self, fd: usize, events: SyscallEventFlags) -> SyscallResult> { let file = self.files .get_mut(&fd) .ok_or_else(|| SyscallError::new(syscall::EBADF))?; match *file { SchemeFile::Setting(_) => return Err(SyscallError::new(syscall::EBADF)), SchemeFile::Socket(ref mut file) => { file.events = events.bits(); file.read_notified = false; // resend missed events file.write_notified = false; } } let mut socket_set = self.socket_set.borrow_mut(); let revents = SyscallEventFlags::from_bits_truncate(file.events(&mut socket_set)); Ok(Some(revents)) } fn fsync(&mut self, fd: usize) -> SyscallResult> { { let _file = self.files .get_mut(&fd) .ok_or_else(|| SyscallError::new(syscall::EBADF))?; } Ok(Some(0)) // TODO Implement fsyncing // self.0.network_fsync() } fn fpath(&mut self, fd: usize, buf: &mut [u8]) -> SyscallResult> { let file = self.files .get_mut(&fd) .ok_or_else(|| SyscallError::new(syscall::EBADF))?; let mut socket_set = self.socket_set.borrow_mut(); let socket = socket_set.get::(file.socket_handle()); socket.fpath(file, buf).map(Some) } fn fcntl(&mut self, fd: usize, cmd: usize, arg: usize) -> SyscallResult> { if let Some(ref mut null) = self.nulls.get_mut(&fd) { match cmd { syscall::F_GETFL => Ok(Some(null.flags)), syscall::F_SETFL => { null.flags = arg & !syscall::O_ACCMODE; Ok(Some(0)) } _ => Err(SyscallError::new(syscall::EINVAL)), } } else { let file = self.files .get_mut(&fd) .ok_or_else(|| SyscallError::new(syscall::EBADF))?; if let SchemeFile::Socket(ref mut socket_file) = *file { match cmd { syscall::F_GETFL => Ok(Some(socket_file.flags)), syscall::F_SETFL => { socket_file.flags = arg & !syscall::O_ACCMODE; Ok(Some(0)) } _ => Err(SyscallError::new(syscall::EINVAL)), } } else { Err(SyscallError::new(syscall::EBADF)) } } } } 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; secs += i64::from(nsecs) / 1_000_000_000; nsecs %= 1_000_000_000; TimeSpec { tv_sec: secs, tv_nsec: nsecs, } }