Fix TCP listening endpoint, fpath formatting, port release while listening:

Now TCPListenEndpoint is stored in the SchemeFile because the
TcpSocket::endpoint() only store endpoints for connected sockets,
not listening ones
This commit is contained in:
Gartox
2023-08-29 17:24:25 +02:00
parent 035bcf1d69
commit d47cdbf1fe
2 changed files with 204 additions and 92 deletions
+143 -72
View File
@@ -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<SettingT: Copy> {
Ttl,
ReadTimeout,
WriteTimeout,
#[allow(dead_code)] Other(SettingT),
#[allow(dead_code)]
Other(SettingT),
}
pub struct SettingFile<SettingT: Copy> {
@@ -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::<SocketT>(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<Self::DataT>, setting: Self::SettingT, buf: &mut [u8]) -> SyscallResult<usize>;
fn set_setting(file: &mut SocketFile<Self::DataT>, setting: Self::SettingT, buf: &[u8]) -> SyscallResult<usize>;
fn get_setting(
file: &SocketFile<Self::DataT>,
setting: Self::SettingT,
buf: &mut [u8],
) -> SyscallResult<usize>;
fn set_setting(
file: &mut SocketFile<Self::DataT>,
setting: Self::SettingT,
buf: &[u8],
) -> SyscallResult<usize>;
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<Self>, data: &mut Self::SchemeDataT) -> SyscallResult<()>;
fn close_file(
&self,
file: &SchemeFile<Self>,
data: &mut Self::SchemeDataT,
) -> SyscallResult<()>;
fn write_buf(&mut self, file: &mut SocketFile<Self::DataT>, buf: &[u8]) -> SyscallResult<Option<usize>>;
fn write_buf(
&mut self,
file: &mut SocketFile<Self::DataT>,
buf: &[u8],
) -> SyscallResult<Option<usize>>;
fn read_buf(&mut self, file: &mut SocketFile<Self::DataT>, buf: &mut [u8]) -> SyscallResult<Option<usize>>;
fn read_buf(
&mut self,
file: &mut SocketFile<Self::DataT>,
buf: &mut [u8],
) -> SyscallResult<Option<usize>>;
fn fpath(&self, file: &SchemeFile<Self>, buf: &mut [u8]) -> SyscallResult<usize>;
@@ -212,7 +243,11 @@ impl<SocketT> SocketScheme<SocketT>
where
SocketT: SchemeSocket + AnySocket<'static>,
{
pub fn new(iface: Interface, socket_set: Rc<RefCell<SocketSet>>, scheme_file: File) -> SocketScheme<SocketT> {
pub fn new(
iface: Interface,
socket_set: Rc<RefCell<SocketSet>>,
scheme_file: File,
) -> SocketScheme<SocketT> {
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<Option<TimeSpec>> {
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<SocketT::SettingT>,
buf: &mut [u8],
) -> SyscallResult<usize> {
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::<SocketT>(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::<SocketT>(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<SocketT::SettingT>,
buf: &[u8],
) -> SyscallResult<usize> {
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::<SocketT>(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::<SocketT>(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<SocketT> syscall::SchemeBlockMut for SocketScheme<SocketT>
where
SocketT: SchemeSocket + AnySocket<'static>,
{
fn open(&mut self, path: &str, flags: usize, uid: u32, _gid: u32) -> SyscallResult<Option<usize>> {
fn open(
&mut self,
path: &str,
flags: usize,
uid: u32,
_gid: u32,
) -> SyscallResult<Option<usize>> {
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<Option<usize>> {
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<Option<usize>> {
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<Option<usize>> {
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<Option<SyscallEventFlags>> {
let file = self.files
fn fevent(
&mut self,
fd: usize,
events: SyscallEventFlags,
) -> SyscallResult<Option<SyscallEventFlags>> {
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<Option<usize>> {
{
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<Option<usize>> {
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::<SocketT>(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))?;
+61 -20
View File
@@ -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<TcpSocket<'static>>;
impl<'a> SchemeSocket for TcpSocket<'a> {
type SchemeDataT = PortSet;
type DataT = ();
type DataT = Option<IpListenEndpoint>;
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::<TcpSocket>(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<Self>,
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<Self>, buf: &mut [u8]) -> SyscallResult<usize> {
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<Self>, buf: &mut [u8]) -> SyscallResult<usize> {
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;