diff --git a/src/smolnetd/scheme/socket.rs b/src/smolnetd/scheme/socket.rs index df7cbfe8f3..c40dda1406 100644 --- a/src/smolnetd/scheme/socket.rs +++ b/src/smolnetd/scheme/socket.rs @@ -1,24 +1,27 @@ use std::cell::RefCell; -use std::collections::BTreeMap; use std::collections::btree_map::Entry; +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, SubAssign}; +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 syscall::{ + Error as SyscallError, EventFlags as SyscallEventFlags, Packet as SyscallPacket, + Result as SyscallResult, SchemeBlockMut, +}; +use super::Interface; +use crate::scheme::smoltcp::iface::SocketHandle; use redox_netstack::error::{Error, Result}; use smoltcp::socket::AnySocket; -use crate::scheme::smoltcp::iface::SocketHandle; -use super::Interface; use super::{post_fevent, SocketSet}; @@ -73,7 +76,8 @@ enum Setting { Ttl, ReadTimeout, WriteTimeout, - #[allow(dead_code)] Other(SettingT), + #[allow(dead_code)] + Other(SettingT), } pub struct SettingFile { @@ -101,7 +105,10 @@ where } } - pub fn events(&mut self, socket_set: &mut SocketSet) -> usize where SocketT: AnySocket<'static> { + pub fn events(&mut self, socket_set: &mut SocketSet) -> usize + where + SocketT: AnySocket<'static>, + { let mut revents = 0; if let &mut SchemeFile::Socket(SocketFile { socket_handle, @@ -113,7 +120,9 @@ where { let socket = socket_set.get::(socket_handle); - if events & syscall::EVENT_READ.bits() == syscall::EVENT_READ.bits() && (socket.can_recv() || !socket.may_recv()) { + 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(); @@ -122,7 +131,9 @@ where *read_notified = false; } - if events & syscall::EVENT_WRITE.bits() == syscall::EVENT_WRITE.bits() && socket.can_send() { + if events & syscall::EVENT_WRITE.bits() == syscall::EVENT_WRITE.bits() + && socket.can_send() + { if !*write_notified { *write_notified = true; revents |= EVENT_WRITE.bits(); @@ -165,22 +176,42 @@ where fn hop_limit(&self) -> u8; fn set_hop_limit(&mut self, hop_limit: u8); - fn get_setting(file: &SocketFile, setting: Self::SettingT, buf: &mut [u8]) -> SyscallResult; - fn set_setting(file: &mut SocketFile, setting: Self::SettingT, buf: &[u8]) -> SyscallResult; + fn get_setting( + file: &SocketFile, + setting: Self::SettingT, + buf: &mut [u8], + ) -> SyscallResult; + fn set_setting( + file: &mut SocketFile, + setting: Self::SettingT, + buf: &[u8], + ) -> SyscallResult; fn new_socket( sockets: &mut SocketSet, path: &str, uid: u32, data: &mut Self::SchemeDataT, - iface: &Interface + iface: &Interface, ) -> SyscallResult<(SocketHandle, Self::DataT)>; - fn close_file(&self, file: &SchemeFile, data: &mut Self::SchemeDataT) -> SyscallResult<()>; + fn close_file( + &self, + file: &SchemeFile, + data: &mut Self::SchemeDataT, + ) -> SyscallResult<()>; - fn write_buf(&mut self, file: &mut SocketFile, buf: &[u8]) -> SyscallResult>; + fn write_buf( + &mut self, + file: &mut SocketFile, + buf: &[u8], + ) -> SyscallResult>; - fn read_buf(&mut self, file: &mut SocketFile, buf: &mut [u8]) -> SyscallResult>; + fn read_buf( + &mut self, + file: &mut SocketFile, + buf: &mut [u8], + ) -> SyscallResult>; fn fpath(&self, file: &SchemeFile, buf: &mut [u8]) -> SyscallResult; @@ -212,7 +243,11 @@ impl SocketScheme where SocketT: SchemeSocket + AnySocket<'static>, { - pub fn new(iface: Interface, socket_set: Rc>, scheme_file: File) -> SocketScheme { + pub fn new( + iface: Interface, + socket_set: Rc>, + scheme_file: File, + ) -> SocketScheme { SocketScheme { next_fd: 1, nulls: BTreeMap::new(), @@ -234,12 +269,14 @@ where Ok(0) => { //TODO: Cleanup must occur break Some(()); - }, + } Ok(_) => (), - Err(err) => if err.kind() == ErrorKind::WouldBlock { - break None; - } else { - return Err(Error::from(err)); + Err(err) => { + if err.kind() == ErrorKind::WouldBlock { + break None; + } else { + return Err(Error::from(err)); + } } } if let Some(a) = self.handle(&mut packet) { @@ -252,7 +289,7 @@ where until: timeout, packet, }); - }, + } Err(err) => { packet.a = (-err.errno) as usize; self.scheme_file.write_all(&packet)?; @@ -301,7 +338,7 @@ where self.wait_queue.remove(i); packet.a = (-syscall::ETIMEDOUT) as usize; self.scheme_file.write_all(&packet)?; - }, + } _ => { i += 1; } @@ -315,15 +352,13 @@ where fn handle_block(&mut self, packet: &mut SyscallPacket) -> SyscallResult> { let fd = packet.b; let (read_timeout, write_timeout) = { - let file = self.files + 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, - )) + Ok((scheme_file.read_timeout, scheme_file.write_timeout)) } else { Err(SyscallError::new(syscall::EBADF)) } @@ -350,7 +385,8 @@ where setting: Setting, buf: &mut [u8], ) -> SyscallResult { - let file = self.files + let file = self + .files .get_mut(&fd) .ok_or_else(|| SyscallError::new(syscall::EBADF))?; let file = match *file { @@ -362,14 +398,16 @@ where 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::Ttl => { + if let Some(hop_limit) = buf.get_mut(0) { + let socket_set = self.socket_set.borrow(); + 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, @@ -397,7 +435,8 @@ where setting: Setting, buf: &[u8], ) -> SyscallResult { - let file = self.files + let file = self + .files .get_mut(&fd) .ok_or_else(|| SyscallError::new(syscall::EBADF))?; let file = match *file { @@ -430,14 +469,16 @@ where }; Ok(count) } - Setting::Ttl => if let Some(hop_limit) = buf.get(0) { - let mut socket_set = self.socket_set.borrow_mut(); - let socket = socket_set.get_mut::(file.socket_handle); - socket.set_hop_limit(*hop_limit); - Ok(1) - } else { - Err(SyscallError::new(syscall::EIO)) - }, + Setting::Ttl => { + if let Some(hop_limit) = buf.get(0) { + let mut socket_set = self.socket_set.borrow_mut(); + let socket = socket_set.get_mut::(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), } } @@ -447,7 +488,13 @@ impl syscall::SchemeBlockMut for SocketScheme where SocketT: SchemeSocket + AnySocket<'static>, { - fn open(&mut self, path: &str, flags: usize, uid: u32, _gid: u32) -> SyscallResult> { + fn open( + &mut self, + path: &str, + flags: usize, + uid: u32, + _gid: u32, + ) -> SyscallResult> { if path.is_empty() { let null = NullFile { flags, @@ -467,7 +514,7 @@ where path, uid, &mut self.scheme_data, - &self.iface + &self.iface, )?; let file = SchemeFile::Socket(SocketFile { @@ -497,7 +544,8 @@ where } let socket_handle = { - let file = self.files + let file = self + .files .get(&fd) .ok_or_else(|| SyscallError::new(syscall::EBADF))?; file.socket_handle() @@ -520,20 +568,22 @@ where Entry::Vacant(_) => { warn!("Closing a socket_handle with no ref"); true - }, - Entry::Occupied(mut e) => if *e.get() == 0 { - warn!("Closing a socket_handle with no ref"); - e.remove(); - true - } else { - *e.get_mut() -= 1; + } + Entry::Occupied(mut e) => { if *e.get() == 0 { + warn!("Closing a socket_handle with no ref"); e.remove(); true } else { - false + *e.get_mut() -= 1; + if *e.get() == 0 { + e.remove(); + true + } else { + false + } } - }, + } }; if remove { @@ -544,7 +594,8 @@ where fn write(&mut self, fd: usize, buf: &[u8]) -> SyscallResult> { let (fd, setting) = { - let file = self.files + let file = self + .files .get_mut(&fd) .ok_or_else(|| SyscallError::new(syscall::EBADF))?; @@ -564,7 +615,8 @@ where fn read(&mut self, fd: usize, buf: &mut [u8]) -> SyscallResult> { let (fd, setting) = { - let file = self.files + let file = self + .files .get_mut(&fd) .ok_or_else(|| SyscallError::new(syscall::EBADF))?; match *file { @@ -584,7 +636,8 @@ where 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 + if let Some((flags, uid, gid)) = self + .nulls .get(&fd) .map(|null| (null.flags, null.uid, null.gid)) { @@ -592,7 +645,8 @@ where } let new_file = { - let file = self.files + let file = self + .files .get_mut(&fd) .ok_or_else(|| SyscallError::new(syscall::EBADF))?; @@ -636,14 +690,23 @@ where if let Some((socket_handle, data)) = update_with { if let SchemeFile::Socket(ref mut file) = *file { + // We replace the socket_handle pointed by file so update the ref_counts + // accordingly + self.ref_counts + .entry(file.socket_handle) + .and_modify(|e| *e = e.saturating_sub(1)) + .or_insert(0); + + *self.ref_counts.entry(socket_handle).or_insert(0) += 1; + file.socket_handle = socket_handle; file.data = data; - } else { - *self.ref_counts.entry(file.socket_handle()).or_insert(0) += 1; } - } else { - *self.ref_counts.entry(file.socket_handle()).or_insert(0) += 1; } + *self + .ref_counts + .entry(new_handle.socket_handle()) + .or_insert(0) += 1; new_handle }; @@ -654,8 +717,13 @@ where Ok(Some(id)) } - fn fevent(&mut self, fd: usize, events: SyscallEventFlags) -> SyscallResult> { - let file = self.files + 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 { @@ -673,7 +741,8 @@ where fn fsync(&mut self, fd: usize) -> SyscallResult> { { - let _file = self.files + let _file = self + .files .get_mut(&fd) .ok_or_else(|| SyscallError::new(syscall::EBADF))?; } @@ -683,11 +752,12 @@ where } fn fpath(&mut self, fd: usize, buf: &mut [u8]) -> SyscallResult> { - let file = self.files + 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_set = self.socket_set.borrow(); let socket = socket_set.get::(file.socket_handle()); socket.fpath(file, buf).map(Some) @@ -704,7 +774,8 @@ where _ => Err(SyscallError::new(syscall::EINVAL)), } } else { - let file = self.files + let file = self + .files .get_mut(&fd) .ok_or_else(|| SyscallError::new(syscall::EBADF))?; diff --git a/src/smolnetd/scheme/tcp.rs b/src/smolnetd/scheme/tcp.rs index 65bcfb190c..e5cf327dfe 100644 --- a/src/smolnetd/scheme/tcp.rs +++ b/src/smolnetd/scheme/tcp.rs @@ -1,19 +1,20 @@ use smoltcp::iface::SocketHandle; use smoltcp::socket::tcp::{Socket as TcpSocket, SocketBuffer as TcpSocketBuffer}; -use smoltcp::wire::IpEndpoint; +use smoltcp::wire::{IpEndpoint, IpListenEndpoint}; +use std::fmt::Write; use std::str; use syscall; use syscall::{Error as SyscallError, Result as SyscallResult}; use super::socket::{DupResult, SchemeFile, SchemeSocket, SocketFile, SocketScheme}; -use super::{parse_endpoint, SocketSet, Interface}; +use super::{parse_endpoint, Interface, SocketSet}; use crate::port_set::PortSet; pub type TcpScheme = SocketScheme>; impl<'a> SchemeSocket for TcpSocket<'a> { type SchemeDataT = PortSet; - type DataT = (); + type DataT = Option; type SettingT = (); fn new_scheme_data() -> Self::SchemeDataT { @@ -61,7 +62,7 @@ impl<'a> SchemeSocket for TcpSocket<'a> { path: &str, uid: u32, port_set: &mut Self::SchemeDataT, - iface: &Interface + iface: &Interface, ) -> SyscallResult<(SocketHandle, Self::DataT)> { trace!("TCP open {}", path); let mut parts = path.split('/'); @@ -90,19 +91,25 @@ impl<'a> SchemeSocket for TcpSocket<'a> { let tcp_socket = socket_set.get_mut::(socket_handle); - if remote_endpoint.is_specified() { + let listen_enpoint = if remote_endpoint.is_specified() { trace!("Connecting tcp {} {}", local_endpoint, remote_endpoint); tcp_socket - .connect(iface.borrow_mut().context(), IpEndpoint::new(remote_endpoint.addr.unwrap(), remote_endpoint.port), local_endpoint) + .connect( + iface.borrow_mut().context(), + IpEndpoint::new(remote_endpoint.addr.unwrap(), remote_endpoint.port), + local_endpoint, + ) .expect("Can't connect tcp socket "); + None } else { trace!("Listening tcp {}", local_endpoint); tcp_socket .listen(local_endpoint) .expect("Can't listen on local endpoint"); - } + Some(local_endpoint) + }; - Ok((socket_handle, ())) + Ok((socket_handle, listen_enpoint)) } fn close_file( @@ -110,8 +117,12 @@ impl<'a> SchemeSocket for TcpSocket<'a> { file: &SchemeFile, port_set: &mut Self::SchemeDataT, ) -> SyscallResult<()> { - if let SchemeFile::Socket(_) = *file { + if let SchemeFile::Socket(SocketFile { data, .. }) = *file { if let Some(endpoint) = self.local_endpoint() { + // Socket was connected on some port + port_set.release_port(endpoint.port); + } else if let Some(endpoint) = data { + // Socket was listening on some port port_set.release_port(endpoint.port); } } @@ -170,7 +181,13 @@ impl<'a> SchemeSocket for TcpSocket<'a> { let file = match path { "listen" => { if let SchemeFile::Socket(ref tcp_handle) = *file { + let Some(listen_enpoint) = tcp_handle.data else { + // This socket is not listening so we can't accept a connection + return Err(SyscallError::new(syscall::EINVAL)); + }; + if !is_active { + // Socket listening but no connection received if tcp_handle.flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK { return Err(SyscallError::new(syscall::EAGAIN)); } else { @@ -178,8 +195,11 @@ impl<'a> SchemeSocket for TcpSocket<'a> { } } trace!("TCP creating new listening socket"); - let new_handle = SchemeFile::Socket(tcp_handle.clone_with_data(())); + // We pass None as data because this new handle is to the active connection so + // not a listening socket + let new_handle = SchemeFile::Socket(tcp_handle.clone_with_data(None)); + // Creating a socket to continue listening let rx_packets = vec![0; 0xffff]; let tx_packets = vec![0; 0xffff]; let rx_buffer = TcpSocketBuffer::new(rx_packets); @@ -195,12 +215,16 @@ impl<'a> SchemeSocket for TcpSocket<'a> { ) .expect("Can't listen on local endpoint"); } + // We got a new connection to the socket so acquire the port port_set.acquire_port( local_endpoint .expect("Socket was active so local endpoint must be set") .port, ); - return Ok(Some((new_handle, Some((new_socket_handle, ()))))); + return Ok(Some(( + new_handle, + Some((new_socket_handle, Some(listen_enpoint))), + ))); } else { return Err(SyscallError::new(syscall::EBADF)); } @@ -208,9 +232,9 @@ impl<'a> SchemeSocket for TcpSocket<'a> { _ => { trace!("TCP dup unknown {}", path); if let SchemeFile::Socket(ref tcp_handle) = *file { - SchemeFile::Socket(tcp_handle.clone_with_data(())) + SchemeFile::Socket(tcp_handle.clone_with_data(tcp_handle.data)) } else { - SchemeFile::Socket(SocketFile::new_with_data(socket_handle, ())) + SchemeFile::Socket(SocketFile::new_with_data(socket_handle, None)) } } }; @@ -224,13 +248,30 @@ impl<'a> SchemeSocket for TcpSocket<'a> { Ok(Some((file, None))) } - fn fpath(&self, _: &SchemeFile, buf: &mut [u8]) -> SyscallResult { - let path = match (self.remote_endpoint(), self.local_endpoint()) { - (Some(remote_endpoint), Some(local_endpoint)) => format!("tcp:{}/{}", remote_endpoint, local_endpoint), - (Some(remote_endpoint), None) => format!("tcp:{}/none", remote_endpoint), - (None, Some(local_endpoint)) => format!("tcp:none/{}", local_endpoint), - (None, None) => "tcp:none/none".into(), - }; + fn fpath(&self, file: &SchemeFile, buf: &mut [u8]) -> SyscallResult { + let unspecified = "0.0.0.0:0"; + let mut path = String::from("tcp:"); + match self.remote_endpoint() { + Some(endpoint) => write!(&mut path, "{}", endpoint).unwrap(), + None => path.push_str(unspecified), + } + path.push('/'); + match (self.local_endpoint(), file) { + (Some(endpoint), _) => write!(&mut path, "{}", endpoint).unwrap(), + ( + None, + SchemeFile::Socket(SocketFile { + data: Some(endpoint), + .. + }), + ) => if endpoint.is_specified() { + write!(&mut path, "{}", endpoint).unwrap() + } else { + write!(&mut path, "0.0.0.0:{}", endpoint.port).unwrap() + }, + _ => path.push_str(unspecified), + } + trace!("fpath: {}", path); let path = path.as_bytes(); let mut i = 0;