netstack: Add shutdown syscall
This commit is contained in:
@@ -171,7 +171,9 @@ impl<'a> SchemeSocket for IcmpSocket<'a> {
|
||||
file: &mut SocketFile<Self::DataT>,
|
||||
buf: &[u8],
|
||||
) -> SyscallResult<usize> {
|
||||
if self.can_send() {
|
||||
if !file.write_enabled {
|
||||
return Err(SyscallError::new(syscall::EPIPE));
|
||||
} else if self.can_send() {
|
||||
match file.data.socket_type {
|
||||
IcmpSocketType::Echo => {
|
||||
if buf.len() < mem::size_of::<u16>() {
|
||||
@@ -207,6 +209,9 @@ impl<'a> SchemeSocket for IcmpSocket<'a> {
|
||||
file: &mut SocketFile<Self::DataT>,
|
||||
buf: &mut [u8],
|
||||
) -> SyscallResult<usize> {
|
||||
if !file.read_enabled {
|
||||
return Ok(0);
|
||||
}
|
||||
while self.can_recv() {
|
||||
let (payload, _) = self.recv().expect("Can't recv icmp packet");
|
||||
let icmp_packet = Icmpv4Packet::new_unchecked(&payload);
|
||||
@@ -283,4 +288,22 @@ impl<'a> SchemeSocket for IcmpSocket<'a> {
|
||||
) -> SyscallResult<usize> {
|
||||
self.fpath(file, buf)
|
||||
}
|
||||
|
||||
fn handle_shutdown(&mut self, file: &mut SchemeFile<Self>, how: usize) -> SyscallResult<usize> {
|
||||
let socket_file = match file {
|
||||
SchemeFile::Socket(ref mut file) => file,
|
||||
_ => return Err(SyscallError::new(syscall::EBADF)),
|
||||
};
|
||||
|
||||
match how {
|
||||
0 => socket_file.read_enabled = false, // SHUT_RD
|
||||
1 => socket_file.write_enabled = false, // SHUT_WR
|
||||
2 => {
|
||||
socket_file.read_enabled = false;
|
||||
socket_file.write_enabled = false;
|
||||
} // SHUT_RDWR
|
||||
_ => return Err(SyscallError::new(syscall::EINVAL)),
|
||||
}
|
||||
Ok(0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +98,9 @@ impl<'a> SchemeSocket for RawSocket<'a> {
|
||||
file: &mut SocketFile<Self::DataT>,
|
||||
buf: &[u8],
|
||||
) -> SyscallResult<usize> {
|
||||
if self.can_send() {
|
||||
if !file.write_enabled {
|
||||
return Err(SyscallError::new(syscall::EPIPE));
|
||||
} else if self.can_send() {
|
||||
self.send_slice(buf).expect("Can't send slice");
|
||||
Ok(buf.len())
|
||||
} else if file.flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK {
|
||||
@@ -113,7 +115,9 @@ impl<'a> SchemeSocket for RawSocket<'a> {
|
||||
file: &mut SocketFile<Self::DataT>,
|
||||
buf: &mut [u8],
|
||||
) -> SyscallResult<usize> {
|
||||
if self.can_recv() {
|
||||
if !file.read_enabled {
|
||||
Ok(0)
|
||||
} else if self.can_recv() {
|
||||
let length = self.recv_slice(buf).expect("Can't receive slice");
|
||||
Ok(length)
|
||||
} else if file.flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK {
|
||||
@@ -152,4 +156,22 @@ impl<'a> SchemeSocket for RawSocket<'a> {
|
||||
) -> SyscallResult<usize> {
|
||||
self.fpath(file, buf)
|
||||
}
|
||||
|
||||
fn handle_shutdown(&mut self, file: &mut SchemeFile<Self>, how: usize) -> SyscallResult<usize> {
|
||||
let socket_file = match file {
|
||||
SchemeFile::Socket(ref mut file) => file,
|
||||
_ => return Err(SyscallError::new(syscall::EBADF)),
|
||||
};
|
||||
|
||||
match how {
|
||||
0 => socket_file.read_enabled = false, // SHUT_RD
|
||||
1 => socket_file.write_enabled = false, // SHUT_WR
|
||||
2 => {
|
||||
socket_file.read_enabled = false;
|
||||
socket_file.write_enabled = false;
|
||||
} // SHUT_RDWR
|
||||
_ => return Err(SyscallError::new(syscall::EINVAL)),
|
||||
}
|
||||
Ok(0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,8 @@ pub struct NullFile {
|
||||
pub flags: usize,
|
||||
pub uid: u32,
|
||||
pub gid: u32,
|
||||
pub read_enabled: bool,
|
||||
pub write_enabled: bool,
|
||||
}
|
||||
|
||||
pub struct SocketFile<DataT> {
|
||||
@@ -51,6 +53,8 @@ pub struct SocketFile<DataT> {
|
||||
write_notified: bool,
|
||||
read_timeout: Option<TimeSpec>,
|
||||
write_timeout: Option<TimeSpec>,
|
||||
pub read_enabled: bool,
|
||||
pub write_enabled: bool,
|
||||
}
|
||||
|
||||
impl<DataT> SocketFile<DataT> {
|
||||
@@ -63,6 +67,8 @@ impl<DataT> SocketFile<DataT> {
|
||||
read_timeout: self.read_timeout,
|
||||
write_timeout: self.write_timeout,
|
||||
socket_handle: self.socket_handle,
|
||||
read_enabled: self.read_enabled,
|
||||
write_enabled: self.write_enabled,
|
||||
data,
|
||||
}
|
||||
}
|
||||
@@ -75,6 +81,8 @@ impl<DataT> SocketFile<DataT> {
|
||||
write_notified: false,
|
||||
read_timeout: None,
|
||||
write_timeout: None,
|
||||
read_enabled: true,
|
||||
write_enabled: true,
|
||||
socket_handle,
|
||||
data,
|
||||
}
|
||||
@@ -226,6 +234,8 @@ where
|
||||
file: &SchemeFile<Self>,
|
||||
payload: &mut [u8],
|
||||
) -> SyscallResult<usize>;
|
||||
|
||||
fn handle_shutdown(&mut self, file: &mut SchemeFile<Self>, how: usize) -> SyscallResult<usize>;
|
||||
}
|
||||
|
||||
pub struct SocketScheme<SocketT>
|
||||
@@ -442,6 +452,32 @@ where
|
||||
|
||||
SocketT::handle_get_peer_name(socket, file, payload)
|
||||
}
|
||||
SocketCall::Shutdown => {
|
||||
let how = metadata[1] as usize;
|
||||
|
||||
if let Some(null_file) = self.nulls.get_mut(&fd) {
|
||||
match how {
|
||||
0 => null_file.read_enabled = false,
|
||||
1 => null_file.write_enabled = false,
|
||||
2 => {
|
||||
null_file.read_enabled = false;
|
||||
null_file.write_enabled = false;
|
||||
}
|
||||
_ => return Err(SyscallError::new(EINVAL)),
|
||||
}
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
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_mut::<SocketT>(file.socket_handle());
|
||||
|
||||
SocketT::handle_shutdown(socket, file, how)
|
||||
}
|
||||
_ => Err(SyscallError::new(EOPNOTSUPP)),
|
||||
}
|
||||
}
|
||||
@@ -452,9 +488,17 @@ where
|
||||
flags: usize,
|
||||
uid: u32,
|
||||
gid: u32,
|
||||
read_enabled: bool,
|
||||
write_enabled: bool,
|
||||
) -> SyscallResult<OpenResult> {
|
||||
if path.is_empty() {
|
||||
let null = NullFile { flags, uid, gid };
|
||||
let null = NullFile {
|
||||
flags,
|
||||
uid,
|
||||
gid,
|
||||
read_enabled,
|
||||
write_enabled,
|
||||
};
|
||||
|
||||
let id = self.next_fd;
|
||||
self.next_fd += 1;
|
||||
@@ -482,6 +526,8 @@ where
|
||||
write_notified: false,
|
||||
write_timeout: None,
|
||||
read_timeout: None,
|
||||
read_enabled: read_enabled,
|
||||
write_enabled: write_enabled,
|
||||
data,
|
||||
});
|
||||
|
||||
@@ -504,7 +550,7 @@ where
|
||||
SocketT: SchemeSocket + AnySocket<'static>,
|
||||
{
|
||||
fn open(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> SyscallResult<OpenResult> {
|
||||
self.open_inner(path, flags, ctx.uid, ctx.gid)
|
||||
self.open_inner(path, flags, ctx.uid, ctx.gid, true, true)
|
||||
}
|
||||
|
||||
fn call(
|
||||
@@ -642,13 +688,19 @@ where
|
||||
fn dup(&mut self, fd: usize, buf: &[u8], _ctx: &CallerCtx) -> SyscallResult<OpenResult> {
|
||||
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))
|
||||
if let Some((flags, uid, gid, read_enabled, write_enabled)) =
|
||||
self.nulls.get(&fd).map(|null| {
|
||||
(
|
||||
null.flags,
|
||||
null.uid,
|
||||
null.gid,
|
||||
null.read_enabled,
|
||||
null.write_enabled,
|
||||
)
|
||||
})
|
||||
{
|
||||
// dup from empty path to a new path
|
||||
return self.open_inner(path, flags, uid, gid);
|
||||
return self.open_inner(path, flags, uid, gid, read_enabled, write_enabled);
|
||||
}
|
||||
|
||||
let new_file = {
|
||||
|
||||
@@ -153,7 +153,9 @@ impl<'a> SchemeSocket for TcpSocket<'a> {
|
||||
file: &mut SocketFile<Self::DataT>,
|
||||
buf: &[u8],
|
||||
) -> SyscallResult<usize> {
|
||||
if !self.is_active() {
|
||||
if !file.write_enabled {
|
||||
return Err(SyscallError::new(syscall::EPIPE));
|
||||
} else if !self.is_active() {
|
||||
Err(SyscallError::new(syscall::ENOTCONN))
|
||||
} else if self.can_send() {
|
||||
self.send_slice(buf).expect("Can't send slice");
|
||||
@@ -170,7 +172,9 @@ impl<'a> SchemeSocket for TcpSocket<'a> {
|
||||
file: &mut SocketFile<Self::DataT>,
|
||||
buf: &mut [u8],
|
||||
) -> SyscallResult<usize> {
|
||||
if !self.is_active() {
|
||||
if !file.read_enabled {
|
||||
Ok(0)
|
||||
} else if !self.is_active() {
|
||||
Err(SyscallError::new(syscall::ENOTCONN))
|
||||
} else if self.can_recv() {
|
||||
let length = self.recv_slice(buf).expect("Can't receive slice");
|
||||
@@ -308,4 +312,26 @@ impl<'a> SchemeSocket for TcpSocket<'a> {
|
||||
) -> SyscallResult<usize> {
|
||||
self.fpath(file, buf)
|
||||
}
|
||||
|
||||
fn handle_shutdown(&mut self, file: &mut SchemeFile<Self>, how: usize) -> SyscallResult<usize> {
|
||||
let socket_file = match file {
|
||||
SchemeFile::Socket(ref mut file) => file,
|
||||
_ => return Err(SyscallError::new(syscall::EBADF)),
|
||||
};
|
||||
|
||||
match how {
|
||||
0 => socket_file.read_enabled = false, // SHUT_RD
|
||||
1 => {
|
||||
socket_file.write_enabled = false;
|
||||
self.close();
|
||||
} // SHUT_WR
|
||||
2 => {
|
||||
socket_file.read_enabled = false;
|
||||
socket_file.write_enabled = false;
|
||||
self.close();
|
||||
} // SHUT_RDWR
|
||||
_ => return Err(SyscallError::new(syscall::EINVAL)),
|
||||
}
|
||||
Ok(0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,6 +144,9 @@ impl<'a> SchemeSocket for UdpSocket<'a> {
|
||||
if !file.data.is_specified() {
|
||||
return Err(SyscallError::new(syscall::EADDRNOTAVAIL));
|
||||
}
|
||||
if !file.write_enabled {
|
||||
return Err(SyscallError::new(syscall::EPIPE));
|
||||
}
|
||||
if self.can_send() {
|
||||
let endpoint = file.data;
|
||||
let endpoint = IpEndpoint::new(
|
||||
@@ -166,7 +169,9 @@ impl<'a> SchemeSocket for UdpSocket<'a> {
|
||||
file: &mut SocketFile<Self::DataT>,
|
||||
buf: &mut [u8],
|
||||
) -> SyscallResult<usize> {
|
||||
if self.can_recv() {
|
||||
if !file.read_enabled {
|
||||
Ok(0)
|
||||
} else if self.can_recv() {
|
||||
let (length, _) = self.recv_slice(buf).expect("Can't receive slice");
|
||||
Ok(length)
|
||||
} else if file.flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK {
|
||||
@@ -257,4 +262,22 @@ impl<'a> SchemeSocket for UdpSocket<'a> {
|
||||
) -> SyscallResult<usize> {
|
||||
self.fpath(file, buf)
|
||||
}
|
||||
|
||||
fn handle_shutdown(&mut self, file: &mut SchemeFile<Self>, how: usize) -> SyscallResult<usize> {
|
||||
let socket_file = match file {
|
||||
SchemeFile::Socket(ref mut file) => file,
|
||||
_ => return Err(SyscallError::new(syscall::EBADF)),
|
||||
};
|
||||
|
||||
match how {
|
||||
0 => socket_file.read_enabled = false, // SHUT_RD
|
||||
1 => socket_file.write_enabled = false, // SHUT_WR
|
||||
2 => {
|
||||
socket_file.read_enabled = false;
|
||||
socket_file.write_enabled = false;
|
||||
} // SHUT_RDWR
|
||||
_ => return Err(SyscallError::new(syscall::EINVAL)),
|
||||
}
|
||||
Ok(0)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user