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<()> {
|
||||
let host_fd = {
|
||||
let fd_ref = current!().file(fd)?;
|
||||
if let Ok(socket) = fd_ref.as_socket() {
|
||||
socket.fd()
|
||||
if let Ok(socket) = fd_ref.as_host_socket() {
|
||||
socket.host_fd()
|
||||
} else if let Ok(eventfd) = fd_ref.as_event() {
|
||||
eventfd.get_host_fd()
|
||||
} 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;
|
||||
}
|
||||
|
||||
if let Ok(socket) = file_ref.as_socket() {
|
||||
let fd = socket.fd() as FileDesc;
|
||||
if let Ok(socket) = file_ref.as_host_socket() {
|
||||
let fd = socket.host_fd() as FileDesc;
|
||||
index_host_pollfds.push(i);
|
||||
host_pollfds.push(PollEvent::new(fd, pollfd.events()));
|
||||
} else if let Ok(eventfd) = file_ref.as_event() {
|
||||
|
@ -2,21 +2,17 @@ use super::*;
|
||||
use std;
|
||||
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::{
|
||||
clear_notifier_status, notify_thread, wait_for_notification, EpollEvent, IoEvent, PollEvent,
|
||||
PollEventFlags, THREAD_NOTIFIERS,
|
||||
};
|
||||
pub use self::iovs::{Iovs, IovsMut, SliceAsLibcIovec};
|
||||
pub use self::msg::{msghdr, msghdr_mut, MsgHdr, MsgHdrMut};
|
||||
pub use self::msg_flags::{MsgHdrFlags, RecvFlags, SendFlags};
|
||||
pub use self::socket_file::{AsSocket, SocketFile};
|
||||
pub use self::socket::{
|
||||
msghdr, msghdr_mut, AddressFamily, AsUnixSocket, FileFlags, HostSocket, HostSocketType, Iovs,
|
||||
IovsMut, MsgHdr, MsgHdrFlags, MsgHdrMut, RecvFlags, SendFlags, SliceAsLibcIovec, SockAddr,
|
||||
SocketType, UnixSocketFile,
|
||||
};
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
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 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> {
|
||||
if let IoctlCmd::SIOCGIFCONF(arg_ref) = cmd {
|
||||
return self.ioctl_getifconf(arg_ref);
|
||||
@ -13,7 +13,7 @@ impl SocketFile {
|
||||
let mut retval: i32 = 0;
|
||||
let status = occlum_ocall_ioctl(
|
||||
&mut retval as *mut i32,
|
||||
self.fd(),
|
||||
self.host_fd(),
|
||||
cmd_num,
|
||||
cmd_arg_ptr,
|
||||
cmd.arg_len(),
|
||||
@ -36,7 +36,7 @@ impl SocketFile {
|
||||
let mut retval: i32 = 0;
|
||||
let status = occlum_ocall_ioctl_repack(
|
||||
&mut retval as *mut i32,
|
||||
self.fd(),
|
||||
self.host_fd(),
|
||||
BuiltinIoctlNum::SIOCGIFCONF as i32,
|
||||
arg_ref.ifc_buf,
|
||||
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 crate::untrusted::{SliceAsMutPtrAndLen, SliceAsPtrAndLen, UntrustedSliceAlloc};
|
||||
|
||||
impl SocketFile {
|
||||
// TODO: need sockaddr type to implement send/sento
|
||||
/*
|
||||
pub fn recv(&self, buf: &mut [u8], flags: MsgHdrFlags) -> Result<usize> {
|
||||
let (bytes_recvd, _) = self.recvfrom(buf, flags, None)?;
|
||||
impl HostSocket {
|
||||
pub fn recv(&self, buf: &mut [u8], flags: RecvFlags) -> Result<usize> {
|
||||
let (bytes_recvd, _) = self.recvfrom(buf, flags)?;
|
||||
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> {
|
||||
// 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
|
||||
let (bytes_recvd, namelen_recvd, controllen_recvd, flags_recvd) = {
|
||||
// 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
|
||||
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
|
||||
@ -47,19 +21,39 @@ impl SocketFile {
|
||||
msg.set_control_len(controllen_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)
|
||||
}
|
||||
|
||||
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,
|
||||
data: &mut [&mut [u8]],
|
||||
flags: RecvFlags,
|
||||
@ -68,7 +62,7 @@ impl SocketFile {
|
||||
) -> Result<(usize, usize, usize, MsgHdrFlags)> {
|
||||
// Prepare the arguments for OCall
|
||||
// Host socket fd
|
||||
let host_fd = self.host_fd;
|
||||
let host_fd = self.host_fd();
|
||||
// Name
|
||||
let (msg_name, msg_namelen) = name.as_mut_ptr_and_len();
|
||||
let msg_name = msg_name as *mut c_void;
|
@ -1,56 +1,57 @@
|
||||
use super::*;
|
||||
|
||||
impl SocketFile {
|
||||
// TODO: need sockaddr type to implement send/sento
|
||||
/*
|
||||
pub fn send(&self, buf: &[u8], flags: MsgFlags) -> Result<usize> {
|
||||
self.sendto(buf, flags, None)
|
||||
impl HostSocket {
|
||||
pub fn send(&self, buf: &[u8], flags: SendFlags) -> 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> {
|
||||
// Copy message's iovecs into untrusted iovecs
|
||||
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,
|
||||
data: &[&[u8]],
|
||||
flags: SendFlags,
|
||||
name: 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> {
|
||||
// Prepare the arguments for OCall
|
||||
let mut retval: isize = 0;
|
||||
// Host socket fd
|
||||
let host_fd = self.host_fd;
|
||||
let host_fd = self.host_fd();
|
||||
// Name
|
||||
let (msg_name, msg_namelen) = name.as_ptr_and_len();
|
||||
let msg_name = msg_name as *const c_void;
|
||||
// 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();
|
||||
// Control
|
||||
let (msg_control, msg_controllen) = control.as_ptr_and_len();
|
||||
@ -73,7 +74,6 @@ impl SocketFile {
|
||||
);
|
||||
assert!(status == sgx_status_t::SGX_SUCCESS);
|
||||
}
|
||||
|
||||
let bytes_sent = if flags.contains(SendFlags::MSG_NOSIGNAL) {
|
||||
try_libc!(retval)
|
||||
} 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(())
|
||||
}
|
||||
|
||||
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.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;
|
||||
|
||||
pub fn do_socket(domain: c_int, socket_type: c_int, protocol: c_int) -> Result<isize> {
|
||||
debug!(
|
||||
"socket: domain: {}, socket_type: 0x{:x}, protocol: {}",
|
||||
domain, socket_type, protocol
|
||||
);
|
||||
let sock_domain = AddressFamily::try_from(domain as u16)?;
|
||||
let file_flags = FileFlags::from_bits_truncate(socket_type);
|
||||
let sock_type = SocketType::try_from(socket_type & (!file_flags.bits()))?;
|
||||
|
||||
let file_ref: Arc<Box<dyn File>> = match domain {
|
||||
libc::AF_LOCAL => {
|
||||
let file_ref: Arc<Box<dyn File>> = match sock_domain {
|
||||
AddressFamily::LOCAL => {
|
||||
let unix_socket = UnixSocketFile::new(socket_type, protocol)?;
|
||||
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))
|
||||
}
|
||||
};
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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(
|
||||
fd: c_int,
|
||||
addr: *const libc::sockaddr,
|
||||
addr_len: libc::socklen_t,
|
||||
) -> Result<isize> {
|
||||
debug!(
|
||||
"connect: fd: {}, addr: {:?}, addr_len: {}",
|
||||
fd, addr, addr_len
|
||||
);
|
||||
// For SOCK_DGRAM sockets not initiated in connection-mode,
|
||||
// if address is a null address for the protocol,
|
||||
// the socket's peer address shall be reset.
|
||||
let need_check: bool = !addr.is_null();
|
||||
if need_check {
|
||||
let addr_set: bool = !addr.is_null();
|
||||
if addr_set {
|
||||
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)?;
|
||||
if let Ok(socket) = file_ref.as_socket() {
|
||||
if need_check {
|
||||
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)
|
||||
if let Ok(socket) = file_ref.as_host_socket() {
|
||||
socket.connect(&addr_option)?;
|
||||
} else if let Ok(unix_socket) = file_ref.as_unix_socket() {
|
||||
let addr = addr as *const libc::sockaddr_un;
|
||||
from_user::check_ptr(addr)?;
|
||||
@ -60,10 +97,11 @@ pub fn do_connect(
|
||||
.to_string_lossy()
|
||||
.into_owned();
|
||||
unix_socket.connect(path)?;
|
||||
Ok(0)
|
||||
} else {
|
||||
return_errno!(EBADF, "not a socket")
|
||||
}
|
||||
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
pub fn do_accept(
|
||||
@ -80,93 +118,55 @@ pub fn do_accept4(
|
||||
addr_len: *mut libc::socklen_t,
|
||||
flags: c_int,
|
||||
) -> Result<isize> {
|
||||
debug!(
|
||||
"accept4: fd: {}, addr: {:?}, addr_len: {:?}, flags: {:#x}",
|
||||
fd, addr, addr_len, flags
|
||||
);
|
||||
|
||||
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 {
|
||||
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_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)?;
|
||||
if let Ok(socket) = file_ref.as_socket() {
|
||||
if need_check {
|
||||
from_user::check_mut_ptr(addr as *mut libc::sockaddr_in)?;
|
||||
let new_fd = if let Ok(socket) = file_ref.as_host_socket() {
|
||||
let (new_socket_file, sock_addr_option) = socket.accept(file_flags)?;
|
||||
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)?;
|
||||
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)
|
||||
new_fd
|
||||
} else if let Ok(unix_socket) = file_ref.as_unix_socket() {
|
||||
let addr = addr as *mut libc::sockaddr_un;
|
||||
if need_check {
|
||||
if addr_set {
|
||||
from_user::check_mut_ptr(addr)?;
|
||||
}
|
||||
// TODO: handle addr
|
||||
let new_socket = unix_socket.accept()?;
|
||||
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)
|
||||
current!().add_file(new_file_ref, false)
|
||||
} else {
|
||||
return_errno!(EBADF, "not a socket")
|
||||
}
|
||||
return_errno!(EBADF, "not a socket");
|
||||
};
|
||||
|
||||
Ok(new_fd as isize)
|
||||
}
|
||||
|
||||
pub fn do_shutdown(fd: c_int, how: c_int) -> Result<isize> {
|
||||
debug!("shutdown: fd: {}, how: {}", fd, how);
|
||||
let file_ref = current!().file(fd as FileDesc)?;
|
||||
if let Ok(socket) = file_ref.as_socket() {
|
||||
let ret = try_libc!(libc::ocall::shutdown(socket.fd(), how));
|
||||
if let Ok(socket) = file_ref.as_host_socket() {
|
||||
let ret = try_libc!(libc::ocall::shutdown(socket.host_fd(), how));
|
||||
Ok(ret as isize)
|
||||
} else {
|
||||
return_errno!(EBADF, "not a 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 {
|
||||
// TODO: support unix socket
|
||||
return_errno!(EBADF, "not a socket")
|
||||
}
|
||||
}
|
||||
@ -183,9 +183,9 @@ pub fn do_setsockopt(
|
||||
fd, level, optname, optval, optlen
|
||||
);
|
||||
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(
|
||||
socket.fd(),
|
||||
socket.host_fd(),
|
||||
level,
|
||||
optname,
|
||||
optval,
|
||||
@ -212,10 +212,10 @@ pub fn do_getsockopt(
|
||||
fd, level, optname, optval, optlen
|
||||
);
|
||||
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(
|
||||
socket.fd(),
|
||||
socket.host_fd(),
|
||||
level,
|
||||
optname,
|
||||
optval,
|
||||
@ -234,8 +234,8 @@ pub fn do_getpeername(
|
||||
fd, addr, addr_len
|
||||
);
|
||||
let file_ref = current!().file(fd as FileDesc)?;
|
||||
if let Ok(socket) = file_ref.as_socket() {
|
||||
let ret = try_libc!(libc::ocall::getpeername(socket.fd(), addr, addr_len));
|
||||
if let Ok(socket) = file_ref.as_host_socket() {
|
||||
let ret = try_libc!(libc::ocall::getpeername(socket.host_fd(), addr, addr_len));
|
||||
Ok(ret as isize)
|
||||
} else if let Ok(unix_socket) = file_ref.as_unix_socket() {
|
||||
warn!("getpeername for unix socket is unimplemented");
|
||||
@ -258,8 +258,8 @@ pub fn do_getsockname(
|
||||
fd, addr, addr_len
|
||||
);
|
||||
let file_ref = current!().file(fd as FileDesc)?;
|
||||
if let Ok(socket) = file_ref.as_socket() {
|
||||
let ret = try_libc!(libc::ocall::getsockname(socket.fd(), addr, addr_len));
|
||||
if let Ok(socket) = file_ref.as_host_socket() {
|
||||
let ret = try_libc!(libc::ocall::getsockname(socket.host_fd(), addr, addr_len));
|
||||
Ok(ret as isize)
|
||||
} else if let Ok(unix_socket) = file_ref.as_unix_socket() {
|
||||
warn!("getsockname for unix socket is unimplemented");
|
||||
@ -277,29 +277,36 @@ pub fn do_sendto(
|
||||
addr: *const libc::sockaddr,
|
||||
addr_len: libc::socklen_t,
|
||||
) -> Result<isize> {
|
||||
debug!(
|
||||
"sendto: fd: {}, base: {:?}, len: {}, flags: {} addr: {:?}, addr_len: {}",
|
||||
fd, base, len, flags, addr, addr_len
|
||||
);
|
||||
if len == 0 {
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
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_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)
|
||||
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 !addr.is_null() || addr_len != 0 {
|
||||
return_errno!(EISCONN, "Only connection-mode socket is supported");
|
||||
}
|
||||
|
||||
if !unix.is_connected() {
|
||||
return_errno!(ENOTCONN, "the socket has not been connected yet");
|
||||
}
|
||||
@ -319,22 +326,42 @@ pub fn do_recvfrom(
|
||||
addr: *mut libc::sockaddr,
|
||||
addr_len: *mut libc::socklen_t,
|
||||
) -> Result<isize> {
|
||||
debug!(
|
||||
"recvfrom: fd: {}, base: {:?}, len: {}, flags: {}, addr: {:?}, addr_len: {:?}",
|
||||
fd, base, len, flags, addr, addr_len
|
||||
);
|
||||
let file_ref = current!().file(fd as FileDesc)?;
|
||||
let socket = file_ref.as_socket()?;
|
||||
if addr.is_null() ^ addr_len.is_null() {
|
||||
return_errno!(EINVAL, "addr and ddr_len should be both null");
|
||||
}
|
||||
|
||||
let ret = try_libc!(libc::ocall::recvfrom(
|
||||
socket.fd(),
|
||||
base,
|
||||
len,
|
||||
flags,
|
||||
addr,
|
||||
addr_len
|
||||
));
|
||||
Ok(ret as isize)
|
||||
from_user::check_array(base as *mut u8, len)?;
|
||||
let mut buf = unsafe { std::slice::from_raw_parts_mut(base as *mut u8, len as usize) };
|
||||
|
||||
// MSG_CTRUNC is a return flag but linux allows it to be set on input flags.
|
||||
// We just ignore it.
|
||||
let recv_flags = RecvFlags::from_bits(flags & !(MsgHdrFlags::MSG_CTRUNC.bits()))
|
||||
.ok_or_else(|| errno!(EINVAL, "invalid flags"))?;
|
||||
|
||||
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(
|
||||
@ -343,27 +370,26 @@ pub fn do_socketpair(
|
||||
protocol: c_int,
|
||||
sv: *mut c_int,
|
||||
) -> Result<isize> {
|
||||
debug!(
|
||||
"socketpair: domain: {}, type:0x{:x}, protocol: {}",
|
||||
domain, socket_type, protocol
|
||||
);
|
||||
let mut sock_pair = unsafe {
|
||||
from_user::check_mut_array(sv, 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) =
|
||||
UnixSocketFile::socketpair(socket_type as i32, protocol as i32)?;
|
||||
|
||||
let current = current!();
|
||||
let mut files = current.files().lock().unwrap();
|
||||
sock_pair[0] = files.put(Arc::new(Box::new(client_socket)), false);
|
||||
sock_pair[1] = files.put(Arc::new(Box::new(server_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)), close_on_spawn);
|
||||
|
||||
debug!("socketpair: ({}, {})", sock_pair[0], sock_pair[1]);
|
||||
Ok(0)
|
||||
} else if (domain == libc::AF_TIPC) {
|
||||
return_errno!(EAFNOSUPPORT, "cluster domain sockets not supported")
|
||||
} else {
|
||||
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)?;
|
||||
if let Ok(socket) = file_ref.as_socket() {
|
||||
if let Ok(socket) = file_ref.as_host_socket() {
|
||||
let msg_c = {
|
||||
from_user::check_ptr(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)?;
|
||||
if let Ok(socket) = file_ref.as_socket() {
|
||||
if let Ok(socket) = file_ref.as_host_socket() {
|
||||
let msg_mut_c = {
|
||||
from_user::check_mut_ptr(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_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_socket, do_socketpair, msghdr, msghdr_mut, AsSocket, AsUnixSocket, EpollEvent, PollEvent,
|
||||
SocketFile, UnixSocketFile,
|
||||
do_socket, do_socketpair, msghdr, msghdr_mut, PollEvent,
|
||||
};
|
||||
use crate::process::{
|
||||
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