Refactor host socket
1. Add Rust memory-safe types, e.g., socket_address, address_family and socket_type; 2. Implement Berkeley Sockets API for HostSocket.
This commit is contained in:
parent
230e6fa380
commit
d590486029
@ -93,8 +93,8 @@ impl EpollFile {
|
|||||||
pub fn control(&self, op: EpollCtlCmd, fd: FileDesc, event: Option<&EpollEvent>) -> Result<()> {
|
pub fn control(&self, op: EpollCtlCmd, fd: FileDesc, event: Option<&EpollEvent>) -> Result<()> {
|
||||||
let host_fd = {
|
let host_fd = {
|
||||||
let fd_ref = current!().file(fd)?;
|
let fd_ref = current!().file(fd)?;
|
||||||
if let Ok(socket) = fd_ref.as_socket() {
|
if let Ok(socket) = fd_ref.as_host_socket() {
|
||||||
socket.fd()
|
socket.host_fd()
|
||||||
} else if let Ok(eventfd) = fd_ref.as_event() {
|
} else if let Ok(eventfd) = fd_ref.as_event() {
|
||||||
eventfd.get_host_fd()
|
eventfd.get_host_fd()
|
||||||
} else if let Ok(epoll_file) = fd_ref.as_epfile() {
|
} else if let Ok(epoll_file) = fd_ref.as_epfile() {
|
||||||
|
@ -112,8 +112,8 @@ pub fn do_poll(pollfds: &mut [PollEvent], timeout: *mut timeval_t) -> Result<usi
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(socket) = file_ref.as_socket() {
|
if let Ok(socket) = file_ref.as_host_socket() {
|
||||||
let fd = socket.fd() as FileDesc;
|
let fd = socket.host_fd() as FileDesc;
|
||||||
index_host_pollfds.push(i);
|
index_host_pollfds.push(i);
|
||||||
host_pollfds.push(PollEvent::new(fd, pollfd.events()));
|
host_pollfds.push(PollEvent::new(fd, pollfd.events()));
|
||||||
} else if let Ok(eventfd) = file_ref.as_event() {
|
} else if let Ok(eventfd) = file_ref.as_event() {
|
||||||
|
@ -2,21 +2,17 @@ use super::*;
|
|||||||
use std;
|
use std;
|
||||||
use untrusted::{SliceAsMutPtrAndLen, SliceAsPtrAndLen, UntrustedSliceAlloc};
|
use untrusted::{SliceAsMutPtrAndLen, SliceAsPtrAndLen, UntrustedSliceAlloc};
|
||||||
|
|
||||||
mod io_multiplexing;
|
|
||||||
mod iovs;
|
|
||||||
mod msg;
|
|
||||||
mod msg_flags;
|
|
||||||
mod socket_file;
|
|
||||||
mod syscalls;
|
|
||||||
mod unix_socket;
|
|
||||||
|
|
||||||
pub use self::io_multiplexing::{
|
pub use self::io_multiplexing::{
|
||||||
clear_notifier_status, notify_thread, wait_for_notification, EpollEvent, IoEvent, PollEvent,
|
clear_notifier_status, notify_thread, wait_for_notification, EpollEvent, IoEvent, PollEvent,
|
||||||
PollEventFlags, THREAD_NOTIFIERS,
|
PollEventFlags, THREAD_NOTIFIERS,
|
||||||
};
|
};
|
||||||
pub use self::iovs::{Iovs, IovsMut, SliceAsLibcIovec};
|
pub use self::socket::{
|
||||||
pub use self::msg::{msghdr, msghdr_mut, MsgHdr, MsgHdrMut};
|
msghdr, msghdr_mut, AddressFamily, AsUnixSocket, FileFlags, HostSocket, HostSocketType, Iovs,
|
||||||
pub use self::msg_flags::{MsgHdrFlags, RecvFlags, SendFlags};
|
IovsMut, MsgHdr, MsgHdrFlags, MsgHdrMut, RecvFlags, SendFlags, SliceAsLibcIovec, SockAddr,
|
||||||
pub use self::socket_file::{AsSocket, SocketFile};
|
SocketType, UnixSocketFile,
|
||||||
|
};
|
||||||
pub use self::syscalls::*;
|
pub use self::syscalls::*;
|
||||||
pub use self::unix_socket::{AsUnixSocket, UnixSocketFile};
|
|
||||||
|
mod io_multiplexing;
|
||||||
|
mod socket;
|
||||||
|
mod syscalls;
|
||||||
|
71
src/libos/src/net/socket/address_family.rs
Normal file
71
src/libos/src/net/socket/address_family.rs
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
use super::*;
|
||||||
|
|
||||||
|
// The protocol family generally is the same as the address family
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
|
#[repr(u16)]
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
pub enum AddressFamily {
|
||||||
|
UNSPEC = 0,
|
||||||
|
LOCAL = 1,
|
||||||
|
/* Hide the families with the same number
|
||||||
|
UNIX = LOCAL,
|
||||||
|
FILE = LOCAL,
|
||||||
|
*/
|
||||||
|
INET = 2,
|
||||||
|
AX25 = 3,
|
||||||
|
IPX = 4,
|
||||||
|
APPLETALK = 5,
|
||||||
|
NETROM = 6,
|
||||||
|
BRIDGE = 7,
|
||||||
|
ATMPVC = 8,
|
||||||
|
X25 = 9,
|
||||||
|
INET6 = 10,
|
||||||
|
ROSE = 11,
|
||||||
|
DECnet = 12,
|
||||||
|
NETBEUI = 13,
|
||||||
|
SECURITY = 14,
|
||||||
|
KEY = 15,
|
||||||
|
NETLINK = 16,
|
||||||
|
/* Hide the family with the same number
|
||||||
|
ROUTE = NETLINK,
|
||||||
|
*/
|
||||||
|
PACKET = 17,
|
||||||
|
ASH = 18,
|
||||||
|
ECONET = 19,
|
||||||
|
ATMSVC = 20,
|
||||||
|
RDS = 21,
|
||||||
|
SNA = 22,
|
||||||
|
IRDA = 23,
|
||||||
|
PPPOX = 24,
|
||||||
|
WANPIPE = 25,
|
||||||
|
LLC = 26,
|
||||||
|
IB = 27,
|
||||||
|
MPLS = 28,
|
||||||
|
CAN = 29,
|
||||||
|
TIPC = 30,
|
||||||
|
BLUETOOTH = 31,
|
||||||
|
IUCV = 32,
|
||||||
|
RXRPC = 33,
|
||||||
|
ISDN = 34,
|
||||||
|
PHONET = 35,
|
||||||
|
IEEE802154 = 36,
|
||||||
|
CAIF = 37,
|
||||||
|
ALG = 38,
|
||||||
|
NFC = 39,
|
||||||
|
VSOCK = 40,
|
||||||
|
KCM = 41,
|
||||||
|
QIPCRTR = 42,
|
||||||
|
SMC = 43,
|
||||||
|
XDP = 44,
|
||||||
|
MAX = 45,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AddressFamily {
|
||||||
|
pub fn try_from(af: u16) -> Result<Self> {
|
||||||
|
if af >= Self::MAX as u16 {
|
||||||
|
return_errno!(EINVAL, "Unknown address family");
|
||||||
|
} else {
|
||||||
|
Ok(unsafe { core::mem::transmute(af) })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -34,3 +34,10 @@ bitflags! {
|
|||||||
const MSG_NOTIFICATION = 0x8000; // Only applicable to SCTP socket
|
const MSG_NOTIFICATION = 0x8000; // Only applicable to SCTP socket
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
pub struct FileFlags: i32 {
|
||||||
|
const SOCK_NONBLOCK = 0x800;
|
||||||
|
const SOCK_CLOEXEC = 0x80000;
|
||||||
|
}
|
||||||
|
}
|
132
src/libos/src/net/socket/host_socket/host_socket.rs
Normal file
132
src/libos/src/net/socket/host_socket/host_socket.rs
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
use super::*;
|
||||||
|
|
||||||
|
use crate::fs::{
|
||||||
|
occlum_ocall_ioctl, AccessMode, CreationFlags, File, FileRef, IoctlCmd, StatusFlags,
|
||||||
|
};
|
||||||
|
use std::any::Any;
|
||||||
|
use std::io::{Read, Seek, SeekFrom, Write};
|
||||||
|
use std::mem;
|
||||||
|
|
||||||
|
/// Native linux socket
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct HostSocket {
|
||||||
|
host_fd: c_int,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HostSocket {
|
||||||
|
pub fn new(
|
||||||
|
domain: AddressFamily,
|
||||||
|
socket_type: SocketType,
|
||||||
|
file_flags: FileFlags,
|
||||||
|
protocol: i32,
|
||||||
|
) -> Result<Self> {
|
||||||
|
let host_fd = try_libc!(libc::ocall::socket(
|
||||||
|
domain as i32,
|
||||||
|
socket_type as i32 | file_flags.bits(),
|
||||||
|
protocol
|
||||||
|
));
|
||||||
|
Ok(Self { host_fd })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn host_fd(&self) -> c_int {
|
||||||
|
self.host_fd
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bind(&self, addr: &SockAddr) -> Result<()> {
|
||||||
|
let (addr_ptr, addr_len) = addr.as_ptr_and_len();
|
||||||
|
|
||||||
|
let ret = try_libc!(libc::ocall::bind(
|
||||||
|
self.host_fd(),
|
||||||
|
addr_ptr as *const libc::sockaddr,
|
||||||
|
addr_len as u32
|
||||||
|
));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn listen(&self, backlog: i32) -> Result<()> {
|
||||||
|
let ret = try_libc!(libc::ocall::listen(self.host_fd(), backlog));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn accept(&self, flags: FileFlags) -> Result<(Self, Option<SockAddr>)> {
|
||||||
|
let mut sockaddr = SockAddr::default();
|
||||||
|
let mut addr_len = sockaddr.len();
|
||||||
|
|
||||||
|
let ret = try_libc!(libc::ocall::accept4(
|
||||||
|
self.host_fd(),
|
||||||
|
sockaddr.as_mut_ptr() as *mut _,
|
||||||
|
&mut addr_len as *mut _ as *mut _,
|
||||||
|
flags.bits()
|
||||||
|
));
|
||||||
|
|
||||||
|
let addr_option = if addr_len != 0 {
|
||||||
|
sockaddr.set_len(addr_len)?;
|
||||||
|
Some(sockaddr)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
Ok((Self { host_fd: ret }, addr_option))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn connect(&self, addr: &Option<SockAddr>) -> Result<()> {
|
||||||
|
debug!("host_fd: {} addr {:?}", self.host_fd(), addr);
|
||||||
|
|
||||||
|
let (addr_ptr, addr_len) = if let Some(sock_addr) = addr {
|
||||||
|
sock_addr.as_ptr_and_len()
|
||||||
|
} else {
|
||||||
|
(std::ptr::null(), 0)
|
||||||
|
};
|
||||||
|
|
||||||
|
let ret = try_libc!(libc::ocall::connect(
|
||||||
|
self.host_fd(),
|
||||||
|
addr_ptr,
|
||||||
|
addr_len as u32
|
||||||
|
));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sendto(
|
||||||
|
&self,
|
||||||
|
buf: &[u8],
|
||||||
|
flags: SendFlags,
|
||||||
|
addr_option: &Option<SockAddr>,
|
||||||
|
) -> Result<usize> {
|
||||||
|
let bufs = vec![buf];
|
||||||
|
let name_option = addr_option.as_ref().map(|addr| addr.as_slice());
|
||||||
|
self.do_sendmsg(&bufs, flags, name_option, None)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn recvfrom(&self, buf: &mut [u8], flags: RecvFlags) -> Result<(usize, Option<SockAddr>)> {
|
||||||
|
let mut sockaddr = SockAddr::default();
|
||||||
|
let mut bufs = vec![buf];
|
||||||
|
let (bytes_recv, addr_len, _, _) =
|
||||||
|
self.do_recvmsg(&mut bufs, flags, Some(sockaddr.as_mut_slice()), None)?;
|
||||||
|
|
||||||
|
let addr_option = if addr_len != 0 {
|
||||||
|
sockaddr.set_len(addr_len)?;
|
||||||
|
Some(sockaddr)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
Ok((bytes_recv, addr_option))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for HostSocket {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let ret = unsafe { libc::ocall::close(self.host_fd) };
|
||||||
|
assert!(ret == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait HostSocketType {
|
||||||
|
fn as_host_socket(&self) -> Result<&HostSocket>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HostSocketType for FileRef {
|
||||||
|
fn as_host_socket(&self) -> Result<&HostSocket> {
|
||||||
|
self.as_any()
|
||||||
|
.downcast_ref::<HostSocket>()
|
||||||
|
.ok_or_else(|| errno!(EBADF, "not a host socket"))
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use fs::{occlum_ocall_ioctl, BuiltinIoctlNum, IoctlCmd};
|
use fs::{occlum_ocall_ioctl, BuiltinIoctlNum, IfConf, IoctlCmd};
|
||||||
|
|
||||||
impl SocketFile {
|
impl HostSocket {
|
||||||
pub(super) fn ioctl_impl(&self, cmd: &mut IoctlCmd) -> Result<i32> {
|
pub(super) fn ioctl_impl(&self, cmd: &mut IoctlCmd) -> Result<i32> {
|
||||||
if let IoctlCmd::SIOCGIFCONF(arg_ref) = cmd {
|
if let IoctlCmd::SIOCGIFCONF(arg_ref) = cmd {
|
||||||
return self.ioctl_getifconf(arg_ref);
|
return self.ioctl_getifconf(arg_ref);
|
||||||
@ -13,7 +13,7 @@ impl SocketFile {
|
|||||||
let mut retval: i32 = 0;
|
let mut retval: i32 = 0;
|
||||||
let status = occlum_ocall_ioctl(
|
let status = occlum_ocall_ioctl(
|
||||||
&mut retval as *mut i32,
|
&mut retval as *mut i32,
|
||||||
self.fd(),
|
self.host_fd(),
|
||||||
cmd_num,
|
cmd_num,
|
||||||
cmd_arg_ptr,
|
cmd_arg_ptr,
|
||||||
cmd.arg_len(),
|
cmd.arg_len(),
|
||||||
@ -36,7 +36,7 @@ impl SocketFile {
|
|||||||
let mut retval: i32 = 0;
|
let mut retval: i32 = 0;
|
||||||
let status = occlum_ocall_ioctl_repack(
|
let status = occlum_ocall_ioctl_repack(
|
||||||
&mut retval as *mut i32,
|
&mut retval as *mut i32,
|
||||||
self.fd(),
|
self.host_fd(),
|
||||||
BuiltinIoctlNum::SIOCGIFCONF as i32,
|
BuiltinIoctlNum::SIOCGIFCONF as i32,
|
||||||
arg_ref.ifc_buf,
|
arg_ref.ifc_buf,
|
||||||
arg_ref.ifc_len,
|
arg_ref.ifc_len,
|
9
src/libos/src/net/socket/host_socket/mod.rs
Normal file
9
src/libos/src/net/socket/host_socket/mod.rs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
use super::*;
|
||||||
|
|
||||||
|
mod host_socket;
|
||||||
|
mod ioctl_impl;
|
||||||
|
mod recv;
|
||||||
|
mod send;
|
||||||
|
mod socket_file;
|
||||||
|
|
||||||
|
pub use self::host_socket::{HostSocket, HostSocketType};
|
@ -1,45 +1,19 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::untrusted::{SliceAsMutPtrAndLen, SliceAsPtrAndLen, UntrustedSliceAlloc};
|
use crate::untrusted::{SliceAsMutPtrAndLen, SliceAsPtrAndLen, UntrustedSliceAlloc};
|
||||||
|
|
||||||
impl SocketFile {
|
impl HostSocket {
|
||||||
// TODO: need sockaddr type to implement send/sento
|
pub fn recv(&self, buf: &mut [u8], flags: RecvFlags) -> Result<usize> {
|
||||||
/*
|
let (bytes_recvd, _) = self.recvfrom(buf, flags)?;
|
||||||
pub fn recv(&self, buf: &mut [u8], flags: MsgHdrFlags) -> Result<usize> {
|
|
||||||
let (bytes_recvd, _) = self.recvfrom(buf, flags, None)?;
|
|
||||||
Ok(bytes_recvd)
|
Ok(bytes_recvd)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn recvfrom(&self, buf: &mut [u8], flags: MsgHdrFlags, src_addr: Option<&mut [u8]>) -> Result<(usize, usize)> {
|
|
||||||
let (bytes_recvd, src_addr_len, _, _) = self.do_recvmsg(
|
|
||||||
&mut buf[..],
|
|
||||||
flags,
|
|
||||||
src_addr,
|
|
||||||
None,
|
|
||||||
)?;
|
|
||||||
Ok((bytes_recvd, src_addr_len))
|
|
||||||
}*/
|
|
||||||
|
|
||||||
pub fn recvmsg<'a, 'b>(&self, msg: &'b mut MsgHdrMut<'a>, flags: RecvFlags) -> Result<usize> {
|
pub fn recvmsg<'a, 'b>(&self, msg: &'b mut MsgHdrMut<'a>, flags: RecvFlags) -> Result<usize> {
|
||||||
// Alloc untrusted iovecs to receive data via OCall
|
|
||||||
let msg_iov = msg.get_iovs();
|
|
||||||
let u_slice_alloc = UntrustedSliceAlloc::new(msg_iov.total_bytes())?;
|
|
||||||
let mut u_slices = msg_iov
|
|
||||||
.as_slices()
|
|
||||||
.iter()
|
|
||||||
.map(|slice| {
|
|
||||||
u_slice_alloc
|
|
||||||
.new_slice_mut(slice.len())
|
|
||||||
.expect("unexpected out of memory error in UntrustedSliceAlloc")
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
let mut u_iovs = IovsMut::new(u_slices);
|
|
||||||
|
|
||||||
// Do OCall-based recvmsg
|
// Do OCall-based recvmsg
|
||||||
let (bytes_recvd, namelen_recvd, controllen_recvd, flags_recvd) = {
|
let (bytes_recvd, namelen_recvd, controllen_recvd, flags_recvd) = {
|
||||||
// Acquire mutable references to the name and control buffers
|
// Acquire mutable references to the name and control buffers
|
||||||
let (name, control) = msg.get_name_and_control_mut();
|
let (iovs, name, control) = msg.get_iovs_name_and_control_mut();
|
||||||
// Fill the data, the name, and the control buffers
|
// Fill the data, the name, and the control buffers
|
||||||
self.do_recvmsg(u_iovs.as_slices_mut(), flags, name, control)?
|
self.do_recvmsg(iovs.as_slices_mut(), flags, name, control)?
|
||||||
};
|
};
|
||||||
|
|
||||||
// Update the output lengths and flags
|
// Update the output lengths and flags
|
||||||
@ -47,19 +21,39 @@ impl SocketFile {
|
|||||||
msg.set_control_len(controllen_recvd)?;
|
msg.set_control_len(controllen_recvd)?;
|
||||||
msg.set_flags(flags_recvd);
|
msg.set_flags(flags_recvd);
|
||||||
|
|
||||||
// Copy data from untrusted iovecs into the output iovecs
|
|
||||||
let mut msg_iov = msg.get_iovs_mut();
|
|
||||||
let mut u_iovs_iter = u_iovs
|
|
||||||
.as_slices()
|
|
||||||
.iter()
|
|
||||||
.flat_map(|slice| slice.iter())
|
|
||||||
.take(bytes_recvd);
|
|
||||||
msg_iov.copy_from_iter(&mut u_iovs_iter);
|
|
||||||
|
|
||||||
Ok(bytes_recvd)
|
Ok(bytes_recvd)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_recvmsg(
|
pub(super) fn do_recvmsg(
|
||||||
|
&self,
|
||||||
|
data: &mut [&mut [u8]],
|
||||||
|
flags: RecvFlags,
|
||||||
|
mut name: Option<&mut [u8]>,
|
||||||
|
mut control: Option<&mut [u8]>,
|
||||||
|
) -> Result<(usize, usize, usize, MsgHdrFlags)> {
|
||||||
|
let data_length = data.iter().map(|s| s.len()).sum();
|
||||||
|
let u_allocator = UntrustedSliceAlloc::new(data_length)?;
|
||||||
|
let mut u_data = {
|
||||||
|
let mut bufs = Vec::new();
|
||||||
|
for ref buf in data.iter() {
|
||||||
|
bufs.push(u_allocator.new_slice_mut(buf.len())?);
|
||||||
|
}
|
||||||
|
bufs
|
||||||
|
};
|
||||||
|
let retval = self.do_recvmsg_untrusted_data(&mut u_data, flags, name, control)?;
|
||||||
|
|
||||||
|
let mut copied = 0;
|
||||||
|
for (i, buf) in data.iter_mut().enumerate() {
|
||||||
|
buf.copy_from_slice(u_data[i]);
|
||||||
|
copied += buf.len();
|
||||||
|
if copied >= retval.0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(retval)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn do_recvmsg_untrusted_data(
|
||||||
&self,
|
&self,
|
||||||
data: &mut [&mut [u8]],
|
data: &mut [&mut [u8]],
|
||||||
flags: RecvFlags,
|
flags: RecvFlags,
|
||||||
@ -68,7 +62,7 @@ impl SocketFile {
|
|||||||
) -> Result<(usize, usize, usize, MsgHdrFlags)> {
|
) -> Result<(usize, usize, usize, MsgHdrFlags)> {
|
||||||
// Prepare the arguments for OCall
|
// Prepare the arguments for OCall
|
||||||
// Host socket fd
|
// Host socket fd
|
||||||
let host_fd = self.host_fd;
|
let host_fd = self.host_fd();
|
||||||
// Name
|
// Name
|
||||||
let (msg_name, msg_namelen) = name.as_mut_ptr_and_len();
|
let (msg_name, msg_namelen) = name.as_mut_ptr_and_len();
|
||||||
let msg_name = msg_name as *mut c_void;
|
let msg_name = msg_name as *mut c_void;
|
@ -1,56 +1,57 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
impl SocketFile {
|
impl HostSocket {
|
||||||
// TODO: need sockaddr type to implement send/sento
|
pub fn send(&self, buf: &[u8], flags: SendFlags) -> Result<usize> {
|
||||||
/*
|
self.sendto(buf, flags, &None)
|
||||||
pub fn send(&self, buf: &[u8], flags: MsgFlags) -> Result<usize> {
|
|
||||||
self.sendto(buf, flags, None)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sendto(&self, buf: &[u8], flags: MsgFlags, dest_addr: Option<&[u8]>) -> Result<usize> {
|
|
||||||
Self::do_sendmsg(
|
|
||||||
self.host_fd,
|
|
||||||
&buf[..],
|
|
||||||
flags,
|
|
||||||
dest_addr,
|
|
||||||
None)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
pub fn sendmsg<'a, 'b>(&self, msg: &'b MsgHdr<'a>, flags: SendFlags) -> Result<usize> {
|
pub fn sendmsg<'a, 'b>(&self, msg: &'b MsgHdr<'a>, flags: SendFlags) -> Result<usize> {
|
||||||
// Copy message's iovecs into untrusted iovecs
|
|
||||||
let msg_iov = msg.get_iovs();
|
let msg_iov = msg.get_iovs();
|
||||||
let u_slice_alloc = UntrustedSliceAlloc::new(msg_iov.total_bytes())?;
|
|
||||||
let u_slices = msg_iov
|
|
||||||
.as_slices()
|
|
||||||
.iter()
|
|
||||||
.map(|src_slice| {
|
|
||||||
u_slice_alloc
|
|
||||||
.new_slice(src_slice)
|
|
||||||
.expect("unexpected out of memory")
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
let u_iovs = Iovs::new(u_slices);
|
|
||||||
|
|
||||||
self.do_sendmsg(u_iovs.as_slices(), flags, msg.get_name(), msg.get_control())
|
self.do_sendmsg(
|
||||||
|
msg_iov.as_slices(),
|
||||||
|
flags,
|
||||||
|
msg.get_name(),
|
||||||
|
msg.get_control(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_sendmsg(
|
pub(super) fn do_sendmsg(
|
||||||
&self,
|
&self,
|
||||||
data: &[&[u8]],
|
data: &[&[u8]],
|
||||||
flags: SendFlags,
|
flags: SendFlags,
|
||||||
name: Option<&[u8]>,
|
name: Option<&[u8]>,
|
||||||
control: Option<&[u8]>,
|
control: Option<&[u8]>,
|
||||||
|
) -> Result<usize> {
|
||||||
|
let data_length = data.iter().map(|s| s.len()).sum();
|
||||||
|
let u_allocator = UntrustedSliceAlloc::new(data_length)?;
|
||||||
|
let u_data = {
|
||||||
|
let mut bufs = Vec::new();
|
||||||
|
for buf in data {
|
||||||
|
bufs.push(u_allocator.new_slice(buf)?);
|
||||||
|
}
|
||||||
|
bufs
|
||||||
|
};
|
||||||
|
|
||||||
|
self.do_sendmsg_untrusted_data(&u_data, flags, name, control)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn do_sendmsg_untrusted_data(
|
||||||
|
&self,
|
||||||
|
u_data: &[&[u8]],
|
||||||
|
flags: SendFlags,
|
||||||
|
name: Option<&[u8]>,
|
||||||
|
control: Option<&[u8]>,
|
||||||
) -> Result<usize> {
|
) -> Result<usize> {
|
||||||
// Prepare the arguments for OCall
|
// Prepare the arguments for OCall
|
||||||
let mut retval: isize = 0;
|
let mut retval: isize = 0;
|
||||||
// Host socket fd
|
// Host socket fd
|
||||||
let host_fd = self.host_fd;
|
let host_fd = self.host_fd();
|
||||||
// Name
|
// Name
|
||||||
let (msg_name, msg_namelen) = name.as_ptr_and_len();
|
let (msg_name, msg_namelen) = name.as_ptr_and_len();
|
||||||
let msg_name = msg_name as *const c_void;
|
let msg_name = msg_name as *const c_void;
|
||||||
// Iovs
|
// Iovs
|
||||||
let raw_iovs: Vec<libc::iovec> = data.iter().map(|slice| slice.as_libc_iovec()).collect();
|
let raw_iovs: Vec<libc::iovec> = u_data.iter().map(|slice| slice.as_libc_iovec()).collect();
|
||||||
let (msg_iov, msg_iovlen) = raw_iovs.as_slice().as_ptr_and_len();
|
let (msg_iov, msg_iovlen) = raw_iovs.as_slice().as_ptr_and_len();
|
||||||
// Control
|
// Control
|
||||||
let (msg_control, msg_controllen) = control.as_ptr_and_len();
|
let (msg_control, msg_controllen) = control.as_ptr_and_len();
|
||||||
@ -73,7 +74,6 @@ impl SocketFile {
|
|||||||
);
|
);
|
||||||
assert!(status == sgx_status_t::SGX_SUCCESS);
|
assert!(status == sgx_status_t::SGX_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
let bytes_sent = if flags.contains(SendFlags::MSG_NOSIGNAL) {
|
let bytes_sent = if flags.contains(SendFlags::MSG_NOSIGNAL) {
|
||||||
try_libc!(retval)
|
try_libc!(retval)
|
||||||
} else {
|
} else {
|
77
src/libos/src/net/socket/host_socket/socket_file.rs
Normal file
77
src/libos/src/net/socket/host_socket/socket_file.rs
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
use super::*;
|
||||||
|
|
||||||
|
use crate::fs::{
|
||||||
|
occlum_ocall_ioctl, AccessMode, CreationFlags, File, FileRef, IoctlCmd, StatusFlags,
|
||||||
|
};
|
||||||
|
use std::any::Any;
|
||||||
|
use std::io::{Read, Seek, SeekFrom, Write};
|
||||||
|
|
||||||
|
//TODO: refactor write syscall to allow zero length with non-zero buffer
|
||||||
|
impl File for HostSocket {
|
||||||
|
fn read(&self, buf: &mut [u8]) -> Result<usize> {
|
||||||
|
self.recv(buf, RecvFlags::empty())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(&self, buf: &[u8]) -> Result<usize> {
|
||||||
|
self.send(buf, SendFlags::empty())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
|
||||||
|
if offset != 0 {
|
||||||
|
return_errno!(ESPIPE, "a nonzero position is not supported");
|
||||||
|
}
|
||||||
|
self.read(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
|
||||||
|
if offset != 0 {
|
||||||
|
return_errno!(ESPIPE, "a nonzero position is not supported");
|
||||||
|
}
|
||||||
|
self.write(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn readv(&self, bufs: &mut [&mut [u8]]) -> Result<usize> {
|
||||||
|
let (bytes_recvd, _, _, _) = self.do_recvmsg(bufs, RecvFlags::empty(), None, None)?;
|
||||||
|
Ok(bytes_recvd)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn writev(&self, bufs: &[&[u8]]) -> Result<usize> {
|
||||||
|
self.do_sendmsg(bufs, SendFlags::empty(), None, None)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn seek(&self, pos: SeekFrom) -> Result<off_t> {
|
||||||
|
return_errno!(ESPIPE, "Socket does not support seek")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ioctl(&self, cmd: &mut IoctlCmd) -> Result<i32> {
|
||||||
|
self.ioctl_impl(cmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_access_mode(&self) -> Result<AccessMode> {
|
||||||
|
Ok(AccessMode::O_RDWR)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_status_flags(&self) -> Result<StatusFlags> {
|
||||||
|
let ret = try_libc!(libc::ocall::fcntl_arg0(self.host_fd(), libc::F_GETFL));
|
||||||
|
Ok(StatusFlags::from_bits_truncate(ret as u32))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_status_flags(&self, new_status_flags: StatusFlags) -> Result<()> {
|
||||||
|
let valid_flags_mask = StatusFlags::O_APPEND
|
||||||
|
| StatusFlags::O_ASYNC
|
||||||
|
| StatusFlags::O_DIRECT
|
||||||
|
| StatusFlags::O_NOATIME
|
||||||
|
| StatusFlags::O_NONBLOCK;
|
||||||
|
let raw_status_flags = (new_status_flags & valid_flags_mask).bits();
|
||||||
|
try_libc!(libc::ocall::fcntl_arg1(
|
||||||
|
self.host_fd(),
|
||||||
|
libc::F_SETFL,
|
||||||
|
raw_status_flags as c_int
|
||||||
|
));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
19
src/libos/src/net/socket/mod.rs
Normal file
19
src/libos/src/net/socket/mod.rs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
use super::*;
|
||||||
|
|
||||||
|
mod address_family;
|
||||||
|
mod flags;
|
||||||
|
mod host_socket;
|
||||||
|
mod iovs;
|
||||||
|
mod msg;
|
||||||
|
mod socket_address;
|
||||||
|
mod socket_type;
|
||||||
|
mod unix_socket;
|
||||||
|
|
||||||
|
pub use self::address_family::AddressFamily;
|
||||||
|
pub use self::flags::{FileFlags, MsgHdrFlags, RecvFlags, SendFlags};
|
||||||
|
pub use self::host_socket::{HostSocket, HostSocketType};
|
||||||
|
pub use self::iovs::{Iovs, IovsMut, SliceAsLibcIovec};
|
||||||
|
pub use self::msg::{msghdr, msghdr_mut, MsgHdr, MsgHdrMut};
|
||||||
|
pub use self::socket_address::SockAddr;
|
||||||
|
pub use self::socket_type::SocketType;
|
||||||
|
pub use self::unix_socket::{AsUnixSocket, UnixSocketFile};
|
@ -196,8 +196,11 @@ impl<'a> MsgHdrMut<'a> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_name_and_control_mut(&mut self) -> (Option<&mut [u8]>, Option<&mut [u8]>) {
|
pub fn get_iovs_name_and_control_mut(
|
||||||
|
&mut self,
|
||||||
|
) -> (&mut IovsMut<'a>, Option<&mut [u8]>, Option<&mut [u8]>) {
|
||||||
(
|
(
|
||||||
|
&mut self.iovs,
|
||||||
self.name.as_mut().map(|name| &mut name[..]),
|
self.name.as_mut().map(|name| &mut name[..]),
|
||||||
self.control.as_mut().map(|control| &mut control[..]),
|
self.control.as_mut().map(|control| &mut control[..]),
|
||||||
)
|
)
|
121
src/libos/src/net/socket/socket_address.rs
Normal file
121
src/libos/src/net/socket/socket_address.rs
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
use super::*;
|
||||||
|
use std::*;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct SockAddr {
|
||||||
|
storage: libc::sockaddr_storage,
|
||||||
|
len: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: add more fields
|
||||||
|
impl fmt::Debug for SockAddr {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("SockAddr")
|
||||||
|
.field(
|
||||||
|
"family",
|
||||||
|
&AddressFamily::try_from(self.storage.ss_family).unwrap(),
|
||||||
|
)
|
||||||
|
.field("len", &self.len)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SockAddr {
|
||||||
|
// Caller should guarentee the sockaddr and addr_len are valid
|
||||||
|
pub unsafe fn try_from_raw(
|
||||||
|
sockaddr: *const libc::sockaddr,
|
||||||
|
addr_len: libc::socklen_t,
|
||||||
|
) -> Result<Self> {
|
||||||
|
if addr_len < std::mem::size_of::<libc::sa_family_t>() as u32 {
|
||||||
|
return_errno!(EINVAL, "the address is too short.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if addr_len > std::mem::size_of::<libc::sockaddr_storage>() as u32 {
|
||||||
|
return_errno!(EINVAL, "the address is too long.");
|
||||||
|
}
|
||||||
|
|
||||||
|
match AddressFamily::try_from((*sockaddr).sa_family)? {
|
||||||
|
AddressFamily::INET => {
|
||||||
|
if addr_len < std::mem::size_of::<libc::sockaddr_in>() as u32 {
|
||||||
|
return_errno!(EINVAL, "short ipv4 address.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AddressFamily::INET6 => {
|
||||||
|
let ipv6_addr_len = std::mem::size_of::<libc::sockaddr_in6>() as u32;
|
||||||
|
// Omit sin6_scope_id when it is not fully provided
|
||||||
|
// 4 represents the size of sin6_scope_id which is not a must
|
||||||
|
if addr_len < ipv6_addr_len - 4 {
|
||||||
|
return_errno!(EINVAL, "wrong ipv6 address length.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => warn!("address family not checked"),
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut storage = mem::MaybeUninit::<libc::sockaddr_storage>::uninit();
|
||||||
|
ptr::copy_nonoverlapping(
|
||||||
|
sockaddr as *const _ as *const u8,
|
||||||
|
storage.as_mut_ptr() as *mut u8,
|
||||||
|
addr_len as usize,
|
||||||
|
);
|
||||||
|
Ok(Self {
|
||||||
|
storage: storage.assume_init(),
|
||||||
|
len: addr_len as usize,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_ptr_and_len(&self) -> (*const libc::sockaddr, usize) {
|
||||||
|
(self.as_ptr(), self.len())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_ptr(&self) -> *const libc::sockaddr {
|
||||||
|
&self.storage as *const _ as *const _
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_mut_ptr(&mut self) -> *mut libc::sockaddr {
|
||||||
|
&mut self.storage as *mut _ as *mut _
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_slice(&self) -> &[u8] {
|
||||||
|
unsafe { std::slice::from_raw_parts(self.as_ptr() as *const u8, self.len()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_mut_slice(&mut self) -> &mut [u8] {
|
||||||
|
unsafe { std::slice::from_raw_parts_mut(self.as_mut_ptr() as *mut u8, self.len()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn copy_to_slice(&self, dst: &mut [u8]) -> usize {
|
||||||
|
let (addr_ptr, addr_len) = self.as_ptr_and_len();
|
||||||
|
let copy_len = std::cmp::min(addr_len, dst.len());
|
||||||
|
dst[0..copy_len].copy_from_slice(unsafe {
|
||||||
|
std::slice::from_raw_parts(addr_ptr as *const u8, copy_len)
|
||||||
|
});
|
||||||
|
copy_len
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.len
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_len(&mut self, len: usize) -> Result<()> {
|
||||||
|
if len > Self::capacity() {
|
||||||
|
return_errno!(EINVAL, "length is too long")
|
||||||
|
} else {
|
||||||
|
self.len = len;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn capacity() -> usize {
|
||||||
|
mem::size_of::<libc::sockaddr_storage>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for SockAddr {
|
||||||
|
fn default() -> Self {
|
||||||
|
let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() };
|
||||||
|
Self {
|
||||||
|
storage: storage,
|
||||||
|
len: mem::size_of::<libc::sockaddr_storage>(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
29
src/libos/src/net/socket/socket_type.rs
Normal file
29
src/libos/src/net/socket/socket_type.rs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
|
#[repr(i32)]
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
pub enum SocketType {
|
||||||
|
STREAM = 1,
|
||||||
|
DGRAM = 2,
|
||||||
|
RAW = 3,
|
||||||
|
RDM = 4,
|
||||||
|
SEQPACKET = 5,
|
||||||
|
DCCP = 6,
|
||||||
|
PACKET = 10,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SocketType {
|
||||||
|
pub fn try_from(sock_type: i32) -> Result<Self> {
|
||||||
|
match sock_type {
|
||||||
|
1 => Ok(SocketType::STREAM),
|
||||||
|
2 => Ok(SocketType::DGRAM),
|
||||||
|
3 => Ok(SocketType::RAW),
|
||||||
|
4 => Ok(SocketType::RDM),
|
||||||
|
5 => Ok(SocketType::SEQPACKET),
|
||||||
|
6 => Ok(SocketType::DCCP),
|
||||||
|
10 => Ok(SocketType::PACKET),
|
||||||
|
_ => return_errno!(EINVAL, "invalid socket type"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,154 +0,0 @@
|
|||||||
use super::*;
|
|
||||||
use crate::fs::IfConf;
|
|
||||||
|
|
||||||
mod ioctl_impl;
|
|
||||||
mod recv;
|
|
||||||
mod send;
|
|
||||||
|
|
||||||
use fs::{AccessMode, CreationFlags, File, FileRef, IoctlCmd, StatusFlags};
|
|
||||||
use std::any::Any;
|
|
||||||
use std::io::{Read, Seek, SeekFrom, Write};
|
|
||||||
|
|
||||||
/// Native Linux socket
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct SocketFile {
|
|
||||||
host_fd: c_int,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SocketFile {
|
|
||||||
pub fn new(domain: c_int, socket_type: c_int, protocol: c_int) -> Result<Self> {
|
|
||||||
let ret = try_libc!(libc::ocall::socket(domain, socket_type, protocol));
|
|
||||||
Ok(SocketFile { host_fd: ret })
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn accept(
|
|
||||||
&self,
|
|
||||||
addr: *mut libc::sockaddr,
|
|
||||||
addr_len: *mut libc::socklen_t,
|
|
||||||
flags: c_int,
|
|
||||||
) -> Result<Self> {
|
|
||||||
let ret = try_libc!(libc::ocall::accept4(self.host_fd, addr, addr_len, flags));
|
|
||||||
Ok(SocketFile { host_fd: ret })
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn fd(&self) -> c_int {
|
|
||||||
self.host_fd
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for SocketFile {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
let ret = unsafe { libc::ocall::close(self.host_fd) };
|
|
||||||
assert!(ret == 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: rewrite read/write/readv/writev as send/recv
|
|
||||||
// TODO: implement readfrom/sendto
|
|
||||||
impl File for SocketFile {
|
|
||||||
fn read(&self, buf: &mut [u8]) -> Result<usize> {
|
|
||||||
let (buf_ptr, buf_len) = buf.as_mut().as_mut_ptr_and_len();
|
|
||||||
let ret = try_libc!(libc::ocall::read(
|
|
||||||
self.host_fd,
|
|
||||||
buf_ptr as *mut c_void,
|
|
||||||
buf_len
|
|
||||||
)) as usize;
|
|
||||||
assert!(ret <= buf_len);
|
|
||||||
Ok(ret)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write(&self, buf: &[u8]) -> Result<usize> {
|
|
||||||
let (buf_ptr, buf_len) = buf.as_ptr_and_len();
|
|
||||||
let ret = try_libc_may_epipe!(libc::ocall::write(
|
|
||||||
self.host_fd,
|
|
||||||
buf_ptr as *const c_void,
|
|
||||||
buf_len
|
|
||||||
)) as usize;
|
|
||||||
assert!(ret <= buf_len);
|
|
||||||
Ok(ret)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_at(&self, _offset: usize, buf: &mut [u8]) -> Result<usize> {
|
|
||||||
self.read(buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_at(&self, _offset: usize, buf: &[u8]) -> Result<usize> {
|
|
||||||
self.write(buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn readv(&self, bufs: &mut [&mut [u8]]) -> Result<usize> {
|
|
||||||
let mut total_len = 0;
|
|
||||||
for buf in bufs {
|
|
||||||
match self.read(buf) {
|
|
||||||
Ok(len) => {
|
|
||||||
total_len += len;
|
|
||||||
}
|
|
||||||
Err(_) if total_len != 0 => break,
|
|
||||||
Err(e) => return Err(e.into()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(total_len)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn writev(&self, bufs: &[&[u8]]) -> Result<usize> {
|
|
||||||
let mut total_len = 0;
|
|
||||||
for buf in bufs {
|
|
||||||
match self.write(buf) {
|
|
||||||
Ok(len) => {
|
|
||||||
total_len += len;
|
|
||||||
}
|
|
||||||
Err(_) if total_len != 0 => break,
|
|
||||||
Err(e) => return Err(e.into()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(total_len)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn seek(&self, pos: SeekFrom) -> Result<off_t> {
|
|
||||||
return_errno!(ESPIPE, "Socket does not support seek")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ioctl(&self, cmd: &mut IoctlCmd) -> Result<i32> {
|
|
||||||
self.ioctl_impl(cmd)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_access_mode(&self) -> Result<AccessMode> {
|
|
||||||
Ok(AccessMode::O_RDWR)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_status_flags(&self) -> Result<StatusFlags> {
|
|
||||||
let ret = try_libc!(libc::ocall::fcntl_arg0(self.fd(), libc::F_GETFL));
|
|
||||||
Ok(StatusFlags::from_bits_truncate(ret as u32))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_status_flags(&self, new_status_flags: StatusFlags) -> Result<()> {
|
|
||||||
let valid_flags_mask = StatusFlags::O_APPEND
|
|
||||||
| StatusFlags::O_ASYNC
|
|
||||||
| StatusFlags::O_DIRECT
|
|
||||||
| StatusFlags::O_NOATIME
|
|
||||||
| StatusFlags::O_NONBLOCK;
|
|
||||||
let raw_status_flags = (new_status_flags & valid_flags_mask).bits();
|
|
||||||
try_libc!(libc::ocall::fcntl_arg1(
|
|
||||||
self.fd(),
|
|
||||||
libc::F_SETFL,
|
|
||||||
raw_status_flags as c_int
|
|
||||||
));
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_any(&self) -> &dyn Any {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait AsSocket {
|
|
||||||
fn as_socket(&self) -> Result<&SocketFile>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AsSocket for FileRef {
|
|
||||||
fn as_socket(&self) -> Result<&SocketFile> {
|
|
||||||
self.as_any()
|
|
||||||
.downcast_ref::<SocketFile>()
|
|
||||||
.ok_or_else(|| errno!(EBADF, "not a socket"))
|
|
||||||
}
|
|
||||||
}
|
|
@ -9,50 +9,87 @@ use time::timeval_t;
|
|||||||
use util::mem_util::from_user;
|
use util::mem_util::from_user;
|
||||||
|
|
||||||
pub fn do_socket(domain: c_int, socket_type: c_int, protocol: c_int) -> Result<isize> {
|
pub fn do_socket(domain: c_int, socket_type: c_int, protocol: c_int) -> Result<isize> {
|
||||||
debug!(
|
let sock_domain = AddressFamily::try_from(domain as u16)?;
|
||||||
"socket: domain: {}, socket_type: 0x{:x}, protocol: {}",
|
let file_flags = FileFlags::from_bits_truncate(socket_type);
|
||||||
domain, socket_type, protocol
|
let sock_type = SocketType::try_from(socket_type & (!file_flags.bits()))?;
|
||||||
);
|
|
||||||
|
|
||||||
let file_ref: Arc<Box<dyn File>> = match domain {
|
let file_ref: Arc<Box<dyn File>> = match sock_domain {
|
||||||
libc::AF_LOCAL => {
|
AddressFamily::LOCAL => {
|
||||||
let unix_socket = UnixSocketFile::new(socket_type, protocol)?;
|
let unix_socket = UnixSocketFile::new(socket_type, protocol)?;
|
||||||
Arc::new(Box::new(unix_socket))
|
Arc::new(Box::new(unix_socket))
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let socket = SocketFile::new(domain, socket_type, protocol)?;
|
let socket = HostSocket::new(sock_domain, sock_type, file_flags, protocol)?;
|
||||||
Arc::new(Box::new(socket))
|
Arc::new(Box::new(socket))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let fd = current!().add_file(file_ref, false);
|
let close_on_spawn = file_flags.contains(FileFlags::SOCK_CLOEXEC);
|
||||||
|
let fd = current!().add_file(file_ref, close_on_spawn);
|
||||||
Ok(fd as isize)
|
Ok(fd as isize)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn do_bind(fd: c_int, addr: *const libc::sockaddr, addr_len: libc::socklen_t) -> Result<isize> {
|
||||||
|
if addr.is_null() || addr_len == 0 {
|
||||||
|
return_errno!(EINVAL, "no address is specified");
|
||||||
|
}
|
||||||
|
from_user::check_array(addr as *const u8, addr_len as usize)?;
|
||||||
|
|
||||||
|
let sock_addr = unsafe { SockAddr::try_from_raw(addr, addr_len)? };
|
||||||
|
trace!("bind to addr: {:?}", sock_addr);
|
||||||
|
|
||||||
|
let file_ref = current!().file(fd as FileDesc)?;
|
||||||
|
if let Ok(socket) = file_ref.as_host_socket() {
|
||||||
|
socket.bind(&sock_addr)?;
|
||||||
|
} else if let Ok(unix_socket) = file_ref.as_unix_socket() {
|
||||||
|
let addr = addr as *const libc::sockaddr_un;
|
||||||
|
from_user::check_ptr(addr)?;
|
||||||
|
let path = from_user::clone_cstring_safely(unsafe { (&*addr).sun_path.as_ptr() })?
|
||||||
|
.to_string_lossy()
|
||||||
|
.into_owned();
|
||||||
|
unix_socket.bind(path)?;
|
||||||
|
} else {
|
||||||
|
return_errno!(EBADF, "not a socket");
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn do_listen(fd: c_int, backlog: c_int) -> Result<isize> {
|
||||||
|
let file_ref = current!().file(fd as FileDesc)?;
|
||||||
|
if let Ok(socket) = file_ref.as_host_socket() {
|
||||||
|
socket.listen(backlog)?;
|
||||||
|
} else if let Ok(unix_socket) = file_ref.as_unix_socket() {
|
||||||
|
unix_socket.listen()?;
|
||||||
|
} else {
|
||||||
|
return_errno!(EBADF, "not a socket");
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn do_connect(
|
pub fn do_connect(
|
||||||
fd: c_int,
|
fd: c_int,
|
||||||
addr: *const libc::sockaddr,
|
addr: *const libc::sockaddr,
|
||||||
addr_len: libc::socklen_t,
|
addr_len: libc::socklen_t,
|
||||||
) -> Result<isize> {
|
) -> Result<isize> {
|
||||||
debug!(
|
|
||||||
"connect: fd: {}, addr: {:?}, addr_len: {}",
|
|
||||||
fd, addr, addr_len
|
|
||||||
);
|
|
||||||
// For SOCK_DGRAM sockets not initiated in connection-mode,
|
// For SOCK_DGRAM sockets not initiated in connection-mode,
|
||||||
// if address is a null address for the protocol,
|
// if address is a null address for the protocol,
|
||||||
// the socket's peer address shall be reset.
|
// the socket's peer address shall be reset.
|
||||||
let need_check: bool = !addr.is_null();
|
let addr_set: bool = !addr.is_null();
|
||||||
if need_check {
|
if addr_set {
|
||||||
from_user::check_array(addr as *const u8, addr_len as usize)?;
|
from_user::check_array(addr as *const u8, addr_len as usize)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let addr_option = if addr_set {
|
||||||
|
Some(unsafe { SockAddr::try_from_raw(addr, addr_len)? })
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
let file_ref = current!().file(fd as FileDesc)?;
|
let file_ref = current!().file(fd as FileDesc)?;
|
||||||
if let Ok(socket) = file_ref.as_socket() {
|
if let Ok(socket) = file_ref.as_host_socket() {
|
||||||
if need_check {
|
socket.connect(&addr_option)?;
|
||||||
from_user::check_ptr(addr as *const libc::sockaddr_in)?;
|
|
||||||
}
|
|
||||||
let ret = try_libc!(libc::ocall::connect(socket.fd(), addr, addr_len));
|
|
||||||
Ok(ret as isize)
|
|
||||||
} else if let Ok(unix_socket) = file_ref.as_unix_socket() {
|
} else if let Ok(unix_socket) = file_ref.as_unix_socket() {
|
||||||
let addr = addr as *const libc::sockaddr_un;
|
let addr = addr as *const libc::sockaddr_un;
|
||||||
from_user::check_ptr(addr)?;
|
from_user::check_ptr(addr)?;
|
||||||
@ -60,10 +97,11 @@ pub fn do_connect(
|
|||||||
.to_string_lossy()
|
.to_string_lossy()
|
||||||
.into_owned();
|
.into_owned();
|
||||||
unix_socket.connect(path)?;
|
unix_socket.connect(path)?;
|
||||||
Ok(0)
|
|
||||||
} else {
|
} else {
|
||||||
return_errno!(EBADF, "not a socket")
|
return_errno!(EBADF, "not a socket")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn do_accept(
|
pub fn do_accept(
|
||||||
@ -80,93 +118,55 @@ pub fn do_accept4(
|
|||||||
addr_len: *mut libc::socklen_t,
|
addr_len: *mut libc::socklen_t,
|
||||||
flags: c_int,
|
flags: c_int,
|
||||||
) -> Result<isize> {
|
) -> Result<isize> {
|
||||||
debug!(
|
let addr_set: bool = !addr.is_null();
|
||||||
"accept4: fd: {}, addr: {:?}, addr_len: {:?}, flags: {:#x}",
|
if addr_set {
|
||||||
fd, addr, addr_len, flags
|
from_user::check_ptr(addr_len)?;
|
||||||
);
|
|
||||||
|
|
||||||
let need_check: bool = !addr.is_null();
|
|
||||||
|
|
||||||
if addr.is_null() ^ addr_len.is_null() {
|
|
||||||
return_errno!(EINVAL, "addr and ddr_len should be both null");
|
|
||||||
}
|
|
||||||
if need_check {
|
|
||||||
from_user::check_mut_array(addr as *mut u8, unsafe { *addr_len } as usize)?;
|
from_user::check_mut_array(addr as *mut u8, unsafe { *addr_len } as usize)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let file_flags = FileFlags::from_bits(flags).ok_or_else(|| errno!(EINVAL, "invalid flags"))?;
|
||||||
|
let close_on_spawn = file_flags.contains(FileFlags::SOCK_CLOEXEC);
|
||||||
|
|
||||||
let file_ref = current!().file(fd as FileDesc)?;
|
let file_ref = current!().file(fd as FileDesc)?;
|
||||||
if let Ok(socket) = file_ref.as_socket() {
|
let new_fd = if let Ok(socket) = file_ref.as_host_socket() {
|
||||||
if need_check {
|
let (new_socket_file, sock_addr_option) = socket.accept(file_flags)?;
|
||||||
from_user::check_mut_ptr(addr as *mut libc::sockaddr_in)?;
|
let new_file_ref: Arc<Box<dyn File>> = Arc::new(Box::new(new_socket_file));
|
||||||
|
let new_fd = current!().add_file(new_file_ref, close_on_spawn);
|
||||||
|
|
||||||
|
if addr_set && sock_addr_option.is_some() {
|
||||||
|
let sock_addr = sock_addr_option.unwrap();
|
||||||
|
let mut buf =
|
||||||
|
unsafe { std::slice::from_raw_parts_mut(addr as *mut u8, *addr_len as usize) };
|
||||||
|
sock_addr.copy_to_slice(&mut buf);
|
||||||
|
unsafe {
|
||||||
|
*addr_len = sock_addr.len() as u32;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
let new_socket = socket.accept(addr, addr_len, flags)?;
|
new_fd
|
||||||
let new_file_ref: Arc<Box<dyn File>> = Arc::new(Box::new(new_socket));
|
|
||||||
let new_fd = current!().add_file(new_file_ref, false);
|
|
||||||
|
|
||||||
Ok(new_fd as isize)
|
|
||||||
} else if let Ok(unix_socket) = file_ref.as_unix_socket() {
|
} else if let Ok(unix_socket) = file_ref.as_unix_socket() {
|
||||||
let addr = addr as *mut libc::sockaddr_un;
|
let addr = addr as *mut libc::sockaddr_un;
|
||||||
if need_check {
|
if addr_set {
|
||||||
from_user::check_mut_ptr(addr)?;
|
from_user::check_mut_ptr(addr)?;
|
||||||
}
|
}
|
||||||
// TODO: handle addr
|
// TODO: handle addr
|
||||||
let new_socket = unix_socket.accept()?;
|
let new_socket = unix_socket.accept()?;
|
||||||
let new_file_ref: Arc<Box<dyn File>> = Arc::new(Box::new(new_socket));
|
let new_file_ref: Arc<Box<dyn File>> = Arc::new(Box::new(new_socket));
|
||||||
let new_fd = current!().add_file(new_file_ref, false);
|
current!().add_file(new_file_ref, false)
|
||||||
|
} else {
|
||||||
|
return_errno!(EBADF, "not a socket");
|
||||||
|
};
|
||||||
|
|
||||||
Ok(new_fd as isize)
|
Ok(new_fd as isize)
|
||||||
} else {
|
|
||||||
return_errno!(EBADF, "not a socket")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn do_shutdown(fd: c_int, how: c_int) -> Result<isize> {
|
pub fn do_shutdown(fd: c_int, how: c_int) -> Result<isize> {
|
||||||
debug!("shutdown: fd: {}, how: {}", fd, how);
|
debug!("shutdown: fd: {}, how: {}", fd, how);
|
||||||
let file_ref = current!().file(fd as FileDesc)?;
|
let file_ref = current!().file(fd as FileDesc)?;
|
||||||
if let Ok(socket) = file_ref.as_socket() {
|
if let Ok(socket) = file_ref.as_host_socket() {
|
||||||
let ret = try_libc!(libc::ocall::shutdown(socket.fd(), how));
|
let ret = try_libc!(libc::ocall::shutdown(socket.host_fd(), how));
|
||||||
Ok(ret as isize)
|
Ok(ret as isize)
|
||||||
} else {
|
} else {
|
||||||
return_errno!(EBADF, "not a socket")
|
// TODO: support unix socket
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn do_bind(fd: c_int, addr: *const libc::sockaddr, addr_len: libc::socklen_t) -> Result<isize> {
|
|
||||||
debug!("bind: fd: {}, addr: {:?}, addr_len: {}", fd, addr, addr_len);
|
|
||||||
if addr.is_null() && addr_len == 0 {
|
|
||||||
return_errno!(EINVAL, "no address is specified");
|
|
||||||
}
|
|
||||||
from_user::check_array(addr as *const u8, addr_len as usize)?;
|
|
||||||
|
|
||||||
let file_ref = current!().file(fd as FileDesc)?;
|
|
||||||
if let Ok(socket) = file_ref.as_socket() {
|
|
||||||
from_user::check_ptr(addr as *const libc::sockaddr_in)?;
|
|
||||||
let ret = try_libc!(libc::ocall::bind(socket.fd(), addr, addr_len));
|
|
||||||
Ok(ret as isize)
|
|
||||||
} else if let Ok(unix_socket) = file_ref.as_unix_socket() {
|
|
||||||
let addr = addr as *const libc::sockaddr_un;
|
|
||||||
from_user::check_ptr(addr)?;
|
|
||||||
let path = from_user::clone_cstring_safely(unsafe { (&*addr).sun_path.as_ptr() })?
|
|
||||||
.to_string_lossy()
|
|
||||||
.into_owned();
|
|
||||||
unix_socket.bind(path)?;
|
|
||||||
Ok(0)
|
|
||||||
} else {
|
|
||||||
return_errno!(EBADF, "not a socket")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn do_listen(fd: c_int, backlog: c_int) -> Result<isize> {
|
|
||||||
debug!("listen: fd: {}, backlog: {}", fd, backlog);
|
|
||||||
let file_ref = current!().file(fd as FileDesc)?;
|
|
||||||
if let Ok(socket) = file_ref.as_socket() {
|
|
||||||
let ret = try_libc!(libc::ocall::listen(socket.fd(), backlog));
|
|
||||||
Ok(ret as isize)
|
|
||||||
} else if let Ok(unix_socket) = file_ref.as_unix_socket() {
|
|
||||||
unix_socket.listen()?;
|
|
||||||
Ok(0)
|
|
||||||
} else {
|
|
||||||
return_errno!(EBADF, "not a socket")
|
return_errno!(EBADF, "not a socket")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -183,9 +183,9 @@ pub fn do_setsockopt(
|
|||||||
fd, level, optname, optval, optlen
|
fd, level, optname, optval, optlen
|
||||||
);
|
);
|
||||||
let file_ref = current!().file(fd as FileDesc)?;
|
let file_ref = current!().file(fd as FileDesc)?;
|
||||||
if let Ok(socket) = file_ref.as_socket() {
|
if let Ok(socket) = file_ref.as_host_socket() {
|
||||||
let ret = try_libc!(libc::ocall::setsockopt(
|
let ret = try_libc!(libc::ocall::setsockopt(
|
||||||
socket.fd(),
|
socket.host_fd(),
|
||||||
level,
|
level,
|
||||||
optname,
|
optname,
|
||||||
optval,
|
optval,
|
||||||
@ -212,10 +212,10 @@ pub fn do_getsockopt(
|
|||||||
fd, level, optname, optval, optlen
|
fd, level, optname, optval, optlen
|
||||||
);
|
);
|
||||||
let file_ref = current!().file(fd as FileDesc)?;
|
let file_ref = current!().file(fd as FileDesc)?;
|
||||||
let socket = file_ref.as_socket()?;
|
let socket = file_ref.as_host_socket()?;
|
||||||
|
|
||||||
let ret = try_libc!(libc::ocall::getsockopt(
|
let ret = try_libc!(libc::ocall::getsockopt(
|
||||||
socket.fd(),
|
socket.host_fd(),
|
||||||
level,
|
level,
|
||||||
optname,
|
optname,
|
||||||
optval,
|
optval,
|
||||||
@ -234,8 +234,8 @@ pub fn do_getpeername(
|
|||||||
fd, addr, addr_len
|
fd, addr, addr_len
|
||||||
);
|
);
|
||||||
let file_ref = current!().file(fd as FileDesc)?;
|
let file_ref = current!().file(fd as FileDesc)?;
|
||||||
if let Ok(socket) = file_ref.as_socket() {
|
if let Ok(socket) = file_ref.as_host_socket() {
|
||||||
let ret = try_libc!(libc::ocall::getpeername(socket.fd(), addr, addr_len));
|
let ret = try_libc!(libc::ocall::getpeername(socket.host_fd(), addr, addr_len));
|
||||||
Ok(ret as isize)
|
Ok(ret as isize)
|
||||||
} else if let Ok(unix_socket) = file_ref.as_unix_socket() {
|
} else if let Ok(unix_socket) = file_ref.as_unix_socket() {
|
||||||
warn!("getpeername for unix socket is unimplemented");
|
warn!("getpeername for unix socket is unimplemented");
|
||||||
@ -258,8 +258,8 @@ pub fn do_getsockname(
|
|||||||
fd, addr, addr_len
|
fd, addr, addr_len
|
||||||
);
|
);
|
||||||
let file_ref = current!().file(fd as FileDesc)?;
|
let file_ref = current!().file(fd as FileDesc)?;
|
||||||
if let Ok(socket) = file_ref.as_socket() {
|
if let Ok(socket) = file_ref.as_host_socket() {
|
||||||
let ret = try_libc!(libc::ocall::getsockname(socket.fd(), addr, addr_len));
|
let ret = try_libc!(libc::ocall::getsockname(socket.host_fd(), addr, addr_len));
|
||||||
Ok(ret as isize)
|
Ok(ret as isize)
|
||||||
} else if let Ok(unix_socket) = file_ref.as_unix_socket() {
|
} else if let Ok(unix_socket) = file_ref.as_unix_socket() {
|
||||||
warn!("getsockname for unix socket is unimplemented");
|
warn!("getsockname for unix socket is unimplemented");
|
||||||
@ -277,29 +277,36 @@ pub fn do_sendto(
|
|||||||
addr: *const libc::sockaddr,
|
addr: *const libc::sockaddr,
|
||||||
addr_len: libc::socklen_t,
|
addr_len: libc::socklen_t,
|
||||||
) -> Result<isize> {
|
) -> Result<isize> {
|
||||||
debug!(
|
if len == 0 {
|
||||||
"sendto: fd: {}, base: {:?}, len: {}, flags: {} addr: {:?}, addr_len: {}",
|
return Ok(0);
|
||||||
fd, base, len, flags, addr, addr_len
|
|
||||||
);
|
|
||||||
from_user::check_array(base as *const u8, len)?;
|
|
||||||
|
|
||||||
let file_ref = current!().file(fd as FileDesc)?;
|
|
||||||
if let Ok(socket) = file_ref.as_socket() {
|
|
||||||
// TODO: check addr and addr_len according to connection mode
|
|
||||||
let ret = try_libc_may_epipe!(libc::ocall::sendto(
|
|
||||||
socket.fd(),
|
|
||||||
base,
|
|
||||||
len,
|
|
||||||
flags,
|
|
||||||
addr,
|
|
||||||
addr_len
|
|
||||||
));
|
|
||||||
Ok(ret as isize)
|
|
||||||
} else if let Ok(unix) = file_ref.as_unix_socket() {
|
|
||||||
if !addr.is_null() || addr_len != 0 {
|
|
||||||
return_errno!(EISCONN, "Only connection-mode socket is supported");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if addr.is_null() ^ (addr_len == 0) {
|
||||||
|
return_errno!(EINVAL, "addr and ddr_len should be both null");
|
||||||
|
}
|
||||||
|
|
||||||
|
from_user::check_array(base as *const u8, len)?;
|
||||||
|
let buf = unsafe { std::slice::from_raw_parts(base as *const u8, len as usize) };
|
||||||
|
|
||||||
|
let addr_set: bool = !addr.is_null();
|
||||||
|
if addr_set {
|
||||||
|
from_user::check_mut_array(addr as *mut u8, addr_len as usize)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let send_flags = SendFlags::from_bits(flags).unwrap();
|
||||||
|
|
||||||
|
let addr_option = if addr_set {
|
||||||
|
Some(unsafe { SockAddr::try_from_raw(addr, addr_len)? })
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let file_ref = current!().file(fd as FileDesc)?;
|
||||||
|
if let Ok(socket) = file_ref.as_host_socket() {
|
||||||
|
socket
|
||||||
|
.sendto(buf, send_flags, &addr_option)
|
||||||
|
.map(|u| u as isize)
|
||||||
|
} else if let Ok(unix) = file_ref.as_unix_socket() {
|
||||||
if !unix.is_connected() {
|
if !unix.is_connected() {
|
||||||
return_errno!(ENOTCONN, "the socket has not been connected yet");
|
return_errno!(ENOTCONN, "the socket has not been connected yet");
|
||||||
}
|
}
|
||||||
@ -319,22 +326,42 @@ pub fn do_recvfrom(
|
|||||||
addr: *mut libc::sockaddr,
|
addr: *mut libc::sockaddr,
|
||||||
addr_len: *mut libc::socklen_t,
|
addr_len: *mut libc::socklen_t,
|
||||||
) -> Result<isize> {
|
) -> Result<isize> {
|
||||||
debug!(
|
if addr.is_null() ^ addr_len.is_null() {
|
||||||
"recvfrom: fd: {}, base: {:?}, len: {}, flags: {}, addr: {:?}, addr_len: {:?}",
|
return_errno!(EINVAL, "addr and ddr_len should be both null");
|
||||||
fd, base, len, flags, addr, addr_len
|
}
|
||||||
);
|
|
||||||
let file_ref = current!().file(fd as FileDesc)?;
|
|
||||||
let socket = file_ref.as_socket()?;
|
|
||||||
|
|
||||||
let ret = try_libc!(libc::ocall::recvfrom(
|
from_user::check_array(base as *mut u8, len)?;
|
||||||
socket.fd(),
|
let mut buf = unsafe { std::slice::from_raw_parts_mut(base as *mut u8, len as usize) };
|
||||||
base,
|
|
||||||
len,
|
// MSG_CTRUNC is a return flag but linux allows it to be set on input flags.
|
||||||
flags,
|
// We just ignore it.
|
||||||
addr,
|
let recv_flags = RecvFlags::from_bits(flags & !(MsgHdrFlags::MSG_CTRUNC.bits()))
|
||||||
addr_len
|
.ok_or_else(|| errno!(EINVAL, "invalid flags"))?;
|
||||||
));
|
|
||||||
Ok(ret as isize)
|
let addr_set: bool = !addr.is_null();
|
||||||
|
if addr_set {
|
||||||
|
from_user::check_ptr(addr_len)?;
|
||||||
|
from_user::check_mut_array(addr as *mut u8, unsafe { *addr_len } as usize)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let file_ref = current!().file(fd as FileDesc)?;
|
||||||
|
let (data_len, sock_addr_option) = if let Ok(socket) = file_ref.as_host_socket() {
|
||||||
|
socket.recvfrom(buf, recv_flags)?
|
||||||
|
} else {
|
||||||
|
return_errno!(EBADF, "not a socket");
|
||||||
|
};
|
||||||
|
|
||||||
|
if addr_set && sock_addr_option.is_some() {
|
||||||
|
let sock_addr = sock_addr_option.unwrap();
|
||||||
|
let mut buf =
|
||||||
|
unsafe { std::slice::from_raw_parts_mut(addr as *mut u8, *addr_len as usize) };
|
||||||
|
sock_addr.copy_to_slice(&mut buf);
|
||||||
|
unsafe {
|
||||||
|
*addr_len = sock_addr.len() as u32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(data_len as isize)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn do_socketpair(
|
pub fn do_socketpair(
|
||||||
@ -343,27 +370,26 @@ pub fn do_socketpair(
|
|||||||
protocol: c_int,
|
protocol: c_int,
|
||||||
sv: *mut c_int,
|
sv: *mut c_int,
|
||||||
) -> Result<isize> {
|
) -> Result<isize> {
|
||||||
debug!(
|
|
||||||
"socketpair: domain: {}, type:0x{:x}, protocol: {}",
|
|
||||||
domain, socket_type, protocol
|
|
||||||
);
|
|
||||||
let mut sock_pair = unsafe {
|
let mut sock_pair = unsafe {
|
||||||
from_user::check_mut_array(sv, 2)?;
|
from_user::check_mut_array(sv, 2)?;
|
||||||
std::slice::from_raw_parts_mut(sv as *mut u32, 2)
|
std::slice::from_raw_parts_mut(sv as *mut u32, 2)
|
||||||
};
|
};
|
||||||
|
|
||||||
if (domain == libc::AF_UNIX) {
|
let file_flags = FileFlags::from_bits_truncate(socket_type);
|
||||||
|
let close_on_spawn = file_flags.contains(FileFlags::SOCK_CLOEXEC);
|
||||||
|
|
||||||
|
let domain = AddressFamily::try_from(domain as u16)?;
|
||||||
|
if (domain == AddressFamily::LOCAL) {
|
||||||
let (client_socket, server_socket) =
|
let (client_socket, server_socket) =
|
||||||
UnixSocketFile::socketpair(socket_type as i32, protocol as i32)?;
|
UnixSocketFile::socketpair(socket_type as i32, protocol as i32)?;
|
||||||
|
|
||||||
let current = current!();
|
let current = current!();
|
||||||
let mut files = current.files().lock().unwrap();
|
let mut files = current.files().lock().unwrap();
|
||||||
sock_pair[0] = files.put(Arc::new(Box::new(client_socket)), false);
|
sock_pair[0] = files.put(Arc::new(Box::new(client_socket)), close_on_spawn);
|
||||||
sock_pair[1] = files.put(Arc::new(Box::new(server_socket)), false);
|
sock_pair[1] = files.put(Arc::new(Box::new(server_socket)), close_on_spawn);
|
||||||
|
|
||||||
debug!("socketpair: ({}, {})", sock_pair[0], sock_pair[1]);
|
debug!("socketpair: ({}, {})", sock_pair[0], sock_pair[1]);
|
||||||
Ok(0)
|
Ok(0)
|
||||||
} else if (domain == libc::AF_TIPC) {
|
|
||||||
return_errno!(EAFNOSUPPORT, "cluster domain sockets not supported")
|
|
||||||
} else {
|
} else {
|
||||||
return_errno!(EAFNOSUPPORT, "domain not supported")
|
return_errno!(EAFNOSUPPORT, "domain not supported")
|
||||||
}
|
}
|
||||||
@ -376,7 +402,7 @@ pub fn do_sendmsg(fd: c_int, msg_ptr: *const msghdr, flags_c: c_int) -> Result<i
|
|||||||
);
|
);
|
||||||
|
|
||||||
let file_ref = current!().file(fd as FileDesc)?;
|
let file_ref = current!().file(fd as FileDesc)?;
|
||||||
if let Ok(socket) = file_ref.as_socket() {
|
if let Ok(socket) = file_ref.as_host_socket() {
|
||||||
let msg_c = {
|
let msg_c = {
|
||||||
from_user::check_ptr(msg_ptr)?;
|
from_user::check_ptr(msg_ptr)?;
|
||||||
let msg_c = unsafe { &*msg_ptr };
|
let msg_c = unsafe { &*msg_ptr };
|
||||||
@ -404,7 +430,7 @@ pub fn do_recvmsg(fd: c_int, msg_mut_ptr: *mut msghdr_mut, flags_c: c_int) -> Re
|
|||||||
);
|
);
|
||||||
|
|
||||||
let file_ref = current!().file(fd as FileDesc)?;
|
let file_ref = current!().file(fd as FileDesc)?;
|
||||||
if let Ok(socket) = file_ref.as_socket() {
|
if let Ok(socket) = file_ref.as_host_socket() {
|
||||||
let msg_mut_c = {
|
let msg_mut_c = {
|
||||||
from_user::check_mut_ptr(msg_mut_ptr)?;
|
from_user::check_mut_ptr(msg_mut_ptr)?;
|
||||||
let msg_mut_c = unsafe { &mut *msg_mut_ptr };
|
let msg_mut_c = unsafe { &mut *msg_mut_ptr };
|
||||||
|
@ -37,8 +37,7 @@ use crate::net::{
|
|||||||
do_accept, do_accept4, do_bind, do_connect, do_epoll_create, do_epoll_create1, do_epoll_ctl,
|
do_accept, do_accept4, do_bind, do_connect, do_epoll_create, do_epoll_create1, do_epoll_ctl,
|
||||||
do_epoll_pwait, do_epoll_wait, do_getpeername, do_getsockname, do_getsockopt, do_listen,
|
do_epoll_pwait, do_epoll_wait, do_getpeername, do_getsockname, do_getsockopt, do_listen,
|
||||||
do_poll, do_recvfrom, do_recvmsg, do_select, do_sendmsg, do_sendto, do_setsockopt, do_shutdown,
|
do_poll, do_recvfrom, do_recvmsg, do_select, do_sendmsg, do_sendto, do_setsockopt, do_shutdown,
|
||||||
do_socket, do_socketpair, msghdr, msghdr_mut, AsSocket, AsUnixSocket, EpollEvent, PollEvent,
|
do_socket, do_socketpair, msghdr, msghdr_mut, PollEvent,
|
||||||
SocketFile, UnixSocketFile,
|
|
||||||
};
|
};
|
||||||
use crate::process::{
|
use crate::process::{
|
||||||
do_arch_prctl, do_clone, do_exit, do_exit_group, do_futex, do_getegid, do_geteuid, do_getgid,
|
do_arch_prctl, do_clone, do_exit, do_exit_group, do_futex, do_getegid, do_geteuid, do_getgid,
|
||||||
|
Loading…
Reference in New Issue
Block a user