[libos] Re-implement unix/host socket and unify net-related structs
This commit is contained in:
parent
f91cd60786
commit
92ec7c334b
@ -14,6 +14,9 @@ bitflags! {
|
|||||||
const HUP = 0x0010; // = POLLHUP
|
const HUP = 0x0010; // = POLLHUP
|
||||||
const NVAL = 0x0020; // = POLLNVAL
|
const NVAL = 0x0020; // = POLLNVAL
|
||||||
const RDHUP = 0x2000; // = POLLRDHUP
|
const RDHUP = 0x2000; // = POLLRDHUP
|
||||||
|
|
||||||
|
/// Events that are always polled even without specifying them.
|
||||||
|
const ALWAYS_POLL = Self::ERR.bits | Self::HUP.bits;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,4 +129,8 @@ impl StatusFlags {
|
|||||||
pub fn is_fast_open(&self) -> bool {
|
pub fn is_fast_open(&self) -> bool {
|
||||||
self.contains(StatusFlags::O_PATH)
|
self.contains(StatusFlags::O_PATH)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_nonblocking(&self) -> bool {
|
||||||
|
self.contains(StatusFlags::O_NONBLOCK)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,7 +99,7 @@ fn get_ifconf_by_host(fd: FileDesc, if_conf: &mut IfConf) -> Result<()> {
|
|||||||
// len: the size of the buf
|
// len: the size of the buf
|
||||||
// recv_len: accepts transferred data length when buf is used to get data from host
|
// recv_len: accepts transferred data length when buf is used to get data from host
|
||||||
//
|
//
|
||||||
fn socket_ocall_ioctl_repack(
|
fn occlum_ocall_ioctl_repack(
|
||||||
ret: *mut i32,
|
ret: *mut i32,
|
||||||
fd: i32,
|
fd: i32,
|
||||||
cmd_num: i32,
|
cmd_num: i32,
|
||||||
@ -112,7 +112,7 @@ fn get_ifconf_by_host(fd: FileDesc, if_conf: &mut IfConf) -> Result<()> {
|
|||||||
try_libc!({
|
try_libc!({
|
||||||
let mut recv_len: i32 = 0;
|
let mut recv_len: i32 = 0;
|
||||||
let mut retval: i32 = 0;
|
let mut retval: i32 = 0;
|
||||||
let status = socket_ocall_ioctl_repack(
|
let status = occlum_ocall_ioctl_repack(
|
||||||
&mut retval as *mut i32,
|
&mut retval as *mut i32,
|
||||||
fd as _,
|
fd as _,
|
||||||
SIOCGIFCONF as _,
|
SIOCGIFCONF as _,
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
use std::cell::Cell;
|
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::sync::Weak;
|
use std::sync::Weak;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use crate::events::{Observer, Waiter, WaiterQueueObserver};
|
use crate::events::{Observer, Waiter, WaiterQueueObserver};
|
||||||
use crate::fs::{AtomicIoEvents, IoEvents};
|
use crate::fs::IoEvents;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::time::{timespec_t, TIMERSLACK};
|
use crate::time::{timespec_t, TIMERSLACK};
|
||||||
|
|
||||||
@ -265,14 +264,14 @@ trait ObserverExt {
|
|||||||
impl ObserverExt for Weak<dyn Observer<IoEvents>> {
|
impl ObserverExt for Weak<dyn Observer<IoEvents>> {
|
||||||
fn register_files<'a>(&self, files_and_events: impl Iterator<Item = &'a (FileRef, IoEvents)>) {
|
fn register_files<'a>(&self, files_and_events: impl Iterator<Item = &'a (FileRef, IoEvents)>) {
|
||||||
for (file, events) in files_and_events {
|
for (file, events) in files_and_events {
|
||||||
let notifier = match file.notifier() {
|
match file.notifier() {
|
||||||
None => continue,
|
None => continue,
|
||||||
Some(notifier) => notifier,
|
Some(notifier) => {
|
||||||
};
|
|
||||||
|
|
||||||
let mask = *events;
|
let mask = *events;
|
||||||
notifier.register(self.clone(), Some(mask), None);
|
notifier.register(self.clone(), Some(mask), None);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unregister_files<'a>(
|
fn unregister_files<'a>(
|
||||||
@ -280,11 +279,12 @@ impl ObserverExt for Weak<dyn Observer<IoEvents>> {
|
|||||||
files_and_events: impl Iterator<Item = &'a (FileRef, IoEvents)>,
|
files_and_events: impl Iterator<Item = &'a (FileRef, IoEvents)>,
|
||||||
) {
|
) {
|
||||||
for (file, events) in files_and_events {
|
for (file, events) in files_and_events {
|
||||||
let notifier = match file.notifier() {
|
match file.notifier() {
|
||||||
None => continue,
|
None => continue,
|
||||||
Some(notifier) => notifier,
|
Some(notifier) => {
|
||||||
};
|
|
||||||
notifier.unregister(self);
|
notifier.unregister(self);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,43 +0,0 @@
|
|||||||
use super::*;
|
|
||||||
|
|
||||||
bitflags! {
|
|
||||||
pub struct SendFlags: i32 {
|
|
||||||
const MSG_OOB = 0x01;
|
|
||||||
const MSG_DONTROUTE = 0x04;
|
|
||||||
const MSG_DONTWAIT = 0x40; // Nonblocking io
|
|
||||||
const MSG_EOR = 0x80; // End of record
|
|
||||||
const MSG_CONFIRM = 0x0800; // Confirm path validity
|
|
||||||
const MSG_NOSIGNAL = 0x4000; // Do not generate SIGPIPE
|
|
||||||
const MSG_MORE = 0x8000; // Sender will send more
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bitflags! {
|
|
||||||
pub struct RecvFlags: i32 {
|
|
||||||
const MSG_OOB = 0x01;
|
|
||||||
const MSG_PEEK = 0x02;
|
|
||||||
const MSG_TRUNC = 0x20;
|
|
||||||
const MSG_DONTWAIT = 0x40; // Nonblocking io
|
|
||||||
const MSG_WAITALL = 0x0100; // Wait for a full request
|
|
||||||
const MSG_ERRQUEUE = 0x2000; // Fetch message from error queue
|
|
||||||
const MSG_CMSG_CLOEXEC = 0x40000000; // Set close_on_exec for file descriptor received through M_RIGHTS
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bitflags! {
|
|
||||||
pub struct MsgHdrFlags: i32 {
|
|
||||||
const MSG_OOB = 0x01;
|
|
||||||
const MSG_CTRUNC = 0x08;
|
|
||||||
const MSG_TRUNC = 0x20;
|
|
||||||
const MSG_EOR = 0x80; // End of record
|
|
||||||
const MSG_ERRQUEUE = 0x2000; // Fetch message from error queue
|
|
||||||
const MSG_NOTIFICATION = 0x8000; // Only applicable to SCTP socket
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bitflags! {
|
|
||||||
pub struct FileFlags: i32 {
|
|
||||||
const SOCK_NONBLOCK = 0x800;
|
|
||||||
const SOCK_CLOEXEC = 0x80000;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,82 +0,0 @@
|
|||||||
use super::*;
|
|
||||||
use fs::{occlum_ocall_ioctl, BuiltinIoctlNum, IfConf, IoctlCmd};
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
let cmd_num = cmd.cmd_num() as c_int;
|
|
||||||
let cmd_arg_ptr = cmd.arg_ptr() as *mut c_void;
|
|
||||||
let ret = try_libc!({
|
|
||||||
let mut retval: i32 = 0;
|
|
||||||
let status = occlum_ocall_ioctl(
|
|
||||||
&mut retval as *mut i32,
|
|
||||||
self.raw_host_fd() as i32,
|
|
||||||
cmd_num,
|
|
||||||
cmd_arg_ptr,
|
|
||||||
cmd.arg_len(),
|
|
||||||
);
|
|
||||||
assert!(status == sgx_status_t::SGX_SUCCESS);
|
|
||||||
retval
|
|
||||||
});
|
|
||||||
// FIXME: add sanity checks for results returned for socket-related ioctls
|
|
||||||
cmd.validate_arg_and_ret_vals(ret)?;
|
|
||||||
Ok(ret)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ioctl_getifconf(&self, arg_ref: &mut IfConf) -> Result<i32> {
|
|
||||||
if !arg_ref.ifc_buf.is_null() && arg_ref.ifc_len == 0 {
|
|
||||||
return Ok(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
let ret = try_libc!({
|
|
||||||
let mut recv_len: i32 = 0;
|
|
||||||
let mut retval: i32 = 0;
|
|
||||||
let status = occlum_ocall_ioctl_repack(
|
|
||||||
&mut retval as *mut i32,
|
|
||||||
self.raw_host_fd() as i32,
|
|
||||||
BuiltinIoctlNum::SIOCGIFCONF as i32,
|
|
||||||
arg_ref.ifc_buf,
|
|
||||||
arg_ref.ifc_len,
|
|
||||||
&mut recv_len as *mut i32,
|
|
||||||
);
|
|
||||||
assert!(status == sgx_status_t::SGX_SUCCESS);
|
|
||||||
// If ifc_req is NULL, SIOCGIFCONF returns the necessary buffer
|
|
||||||
// size in bytes for receiving all available addresses in ifc_len
|
|
||||||
// which is irrelevant to the orginal ifc_len.
|
|
||||||
if !arg_ref.ifc_buf.is_null() {
|
|
||||||
assert!(arg_ref.ifc_len >= recv_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
arg_ref.ifc_len = recv_len;
|
|
||||||
retval
|
|
||||||
});
|
|
||||||
Ok(ret)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
// Used to ioctl arguments with pointer members.
|
|
||||||
//
|
|
||||||
// Before the call the area the pointers points to should be assembled into
|
|
||||||
// one continous memory block. Then the block is repacked to ioctl arguments
|
|
||||||
// in the ocall implementation in host.
|
|
||||||
//
|
|
||||||
// ret: holds the return value of ioctl in host
|
|
||||||
// fd: the host fd for the device
|
|
||||||
// cmd_num: request number of the ioctl
|
|
||||||
// buf: the data to exchange with host
|
|
||||||
// len: the size of the buf
|
|
||||||
// recv_len: accepts transferred data length when buf is used to get data from host
|
|
||||||
//
|
|
||||||
fn occlum_ocall_ioctl_repack(
|
|
||||||
ret: *mut i32,
|
|
||||||
fd: c_int,
|
|
||||||
cmd_num: c_int,
|
|
||||||
buf: *const u8,
|
|
||||||
len: i32,
|
|
||||||
recv_len: *mut i32,
|
|
||||||
) -> sgx_status_t;
|
|
||||||
}
|
|
@ -1,18 +1,16 @@
|
|||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::io::{Read, Seek, SeekFrom, Write};
|
use std::io::{Read, Seek, SeekFrom, Write};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
use atomic::Atomic;
|
use atomic::Atomic;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::fs::{
|
use crate::fs::{
|
||||||
occlum_ocall_ioctl, AccessMode, CreationFlags, File, FileRef, HostFd, IoEvents, IoNotifier,
|
occlum_ocall_ioctl, AccessMode, CreationFlags, File, FileRef, HostFd, IoEvents, IoNotifier,
|
||||||
IoctlCmd, StatusFlags,
|
IoctlRawCmd, StatusFlags,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::process::IO_BUF_SIZE;
|
use crate::process::IO_BUF_SIZE;
|
||||||
|
|
||||||
mod ioctl_impl;
|
|
||||||
mod recv;
|
mod recv;
|
||||||
mod send;
|
mod send;
|
||||||
mod socket_file;
|
mod socket_file;
|
||||||
@ -27,14 +25,14 @@ pub struct HostSocket {
|
|||||||
|
|
||||||
impl HostSocket {
|
impl HostSocket {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
domain: AddressFamily,
|
domain: Domain,
|
||||||
socket_type: SocketType,
|
socket_type: Type,
|
||||||
file_flags: FileFlags,
|
socket_flags: SocketFlags,
|
||||||
protocol: i32,
|
protocol: i32,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
let raw_host_fd = try_libc!(libc::ocall::socket(
|
let raw_host_fd = try_libc!(libc::ocall::socket(
|
||||||
domain as i32,
|
domain as i32,
|
||||||
socket_type as i32 | file_flags.bits(),
|
socket_type as i32 | socket_flags.bits(),
|
||||||
protocol
|
protocol
|
||||||
)) as FileDesc;
|
)) as FileDesc;
|
||||||
let host_fd = HostFd::new(raw_host_fd);
|
let host_fd = HostFd::new(raw_host_fd);
|
||||||
@ -51,7 +49,7 @@ impl HostSocket {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bind(&self, addr: &SockAddr) -> Result<()> {
|
pub fn bind(&self, addr: &RawAddr) -> Result<()> {
|
||||||
let (addr_ptr, addr_len) = addr.as_ptr_and_len();
|
let (addr_ptr, addr_len) = addr.as_ptr_and_len();
|
||||||
|
|
||||||
let ret = try_libc!(libc::ocall::bind(
|
let ret = try_libc!(libc::ocall::bind(
|
||||||
@ -67,8 +65,8 @@ impl HostSocket {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn accept(&self, flags: FileFlags) -> Result<(Self, Option<SockAddr>)> {
|
pub fn accept(&self, flags: SocketFlags) -> Result<(Self, Option<RawAddr>)> {
|
||||||
let mut sockaddr = SockAddr::default();
|
let mut sockaddr = RawAddr::default();
|
||||||
let mut addr_len = sockaddr.len();
|
let mut addr_len = sockaddr.len();
|
||||||
|
|
||||||
let raw_host_fd = try_libc!(libc::ocall::accept4(
|
let raw_host_fd = try_libc!(libc::ocall::accept4(
|
||||||
@ -88,7 +86,33 @@ impl HostSocket {
|
|||||||
Ok((HostSocket::from_host_fd(host_fd)?, addr_option))
|
Ok((HostSocket::from_host_fd(host_fd)?, addr_option))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn connect(&self, addr: &Option<SockAddr>) -> Result<()> {
|
pub fn addr(&self) -> Result<RawAddr> {
|
||||||
|
let mut sockaddr = RawAddr::default();
|
||||||
|
let mut addr_len = sockaddr.len();
|
||||||
|
try_libc!(libc::ocall::getsockname(
|
||||||
|
self.raw_host_fd() as i32,
|
||||||
|
sockaddr.as_mut_ptr() as *mut _,
|
||||||
|
&mut addr_len as *mut _ as *mut _,
|
||||||
|
));
|
||||||
|
|
||||||
|
sockaddr.set_len(addr_len)?;
|
||||||
|
Ok(sockaddr)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn peer_addr(&self) -> Result<RawAddr> {
|
||||||
|
let mut sockaddr = RawAddr::default();
|
||||||
|
let mut addr_len = sockaddr.len();
|
||||||
|
try_libc!(libc::ocall::getpeername(
|
||||||
|
self.raw_host_fd() as i32,
|
||||||
|
sockaddr.as_mut_ptr() as *mut _,
|
||||||
|
&mut addr_len as *mut _ as *mut _,
|
||||||
|
));
|
||||||
|
|
||||||
|
sockaddr.set_len(addr_len)?;
|
||||||
|
Ok(sockaddr)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn connect(&self, addr: &Option<RawAddr>) -> Result<()> {
|
||||||
debug!("connect: host_fd: {}, addr {:?}", self.raw_host_fd(), addr);
|
debug!("connect: host_fd: {}, addr {:?}", self.raw_host_fd(), addr);
|
||||||
|
|
||||||
let (addr_ptr, addr_len) = if let Some(sock_addr) = addr {
|
let (addr_ptr, addr_len) = if let Some(sock_addr) = addr {
|
||||||
@ -109,34 +133,29 @@ impl HostSocket {
|
|||||||
&self,
|
&self,
|
||||||
buf: &[u8],
|
buf: &[u8],
|
||||||
flags: SendFlags,
|
flags: SendFlags,
|
||||||
addr_option: &Option<SockAddr>,
|
addr_option: &Option<RawAddr>,
|
||||||
) -> Result<usize> {
|
) -> Result<usize> {
|
||||||
let bufs = vec![buf];
|
let bufs = vec![buf];
|
||||||
let name_option = addr_option.as_ref().map(|addr| addr.as_slice());
|
self.sendmsg(&bufs, flags, addr_option, None)
|
||||||
self.do_sendmsg(&bufs, flags, name_option, None)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn recvfrom(&self, buf: &mut [u8], flags: RecvFlags) -> Result<(usize, Option<SockAddr>)> {
|
pub fn recvfrom(&self, buf: &mut [u8], flags: RecvFlags) -> Result<(usize, Option<RawAddr>)> {
|
||||||
let mut sockaddr = SockAddr::default();
|
let mut sockaddr = RawAddr::default();
|
||||||
let mut bufs = vec![buf];
|
let mut bufs = vec![buf];
|
||||||
let (bytes_recv, addr_len, _, _) =
|
let (bytes_recv, recv_addr, _, _) = self.recvmsg(&mut bufs, flags, None)?;
|
||||||
self.do_recvmsg(&mut bufs, flags, Some(sockaddr.as_mut_slice()), None)?;
|
|
||||||
|
|
||||||
let addr_option = if addr_len != 0 {
|
Ok((bytes_recv, recv_addr))
|
||||||
sockaddr.set_len(addr_len)?;
|
|
||||||
Some(sockaddr)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
Ok((bytes_recv, addr_option))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn raw_host_fd(&self) -> FileDesc {
|
pub fn raw_host_fd(&self) -> FileDesc {
|
||||||
self.host_fd.to_raw()
|
self.host_fd.to_raw()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn shutdown(&self, how: HowToShut) -> Result<()> {
|
pub fn shutdown(&self, how: Shutdown) -> Result<()> {
|
||||||
try_libc!(libc::ocall::shutdown(self.raw_host_fd() as i32, how.bits()));
|
try_libc!(libc::ocall::shutdown(
|
||||||
|
self.raw_host_fd() as i32,
|
||||||
|
how.to_c() as i32
|
||||||
|
));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,30 +7,12 @@ impl HostSocket {
|
|||||||
Ok(bytes_recvd)
|
Ok(bytes_recvd)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn recvmsg<'a, 'b>(&self, msg: &'b mut MsgHdrMut<'a>, flags: RecvFlags) -> Result<usize> {
|
pub fn recvmsg(
|
||||||
// Do OCall-based recvmsg
|
|
||||||
let (bytes_recvd, namelen_recvd, controllen_recvd, flags_recvd) = {
|
|
||||||
// Acquire mutable references to the name and control buffers
|
|
||||||
let (iovs, name, control) = msg.get_iovs_name_and_control_mut();
|
|
||||||
// Fill the data, the name, and the control buffers
|
|
||||||
self.do_recvmsg(iovs.as_slices_mut(), flags, name, control)?
|
|
||||||
};
|
|
||||||
|
|
||||||
// Update the output lengths and flags
|
|
||||||
msg.set_name_len(namelen_recvd)?;
|
|
||||||
msg.set_control_len(controllen_recvd)?;
|
|
||||||
msg.set_flags(flags_recvd);
|
|
||||||
|
|
||||||
Ok(bytes_recvd)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn do_recvmsg(
|
|
||||||
&self,
|
&self,
|
||||||
data: &mut [&mut [u8]],
|
data: &mut [&mut [u8]],
|
||||||
flags: RecvFlags,
|
flags: RecvFlags,
|
||||||
mut name: Option<&mut [u8]>,
|
control: Option<&mut [u8]>,
|
||||||
mut control: Option<&mut [u8]>,
|
) -> Result<(usize, Option<RawAddr>, MsgFlags, usize)> {
|
||||||
) -> Result<(usize, usize, usize, MsgHdrFlags)> {
|
|
||||||
let current = current!();
|
let current = current!();
|
||||||
let data_length = data.iter().map(|s| s.len()).sum();
|
let data_length = data.iter().map(|s| s.len()).sum();
|
||||||
let mut ocall_alloc;
|
let mut ocall_alloc;
|
||||||
@ -52,7 +34,7 @@ impl HostSocket {
|
|||||||
}
|
}
|
||||||
bufs
|
bufs
|
||||||
};
|
};
|
||||||
let retval = self.do_recvmsg_untrusted_data(&mut u_data, flags, name, control)?;
|
let retval = self.do_recvmsg_untrusted_data(&mut u_data, flags, control)?;
|
||||||
|
|
||||||
let mut remain = retval.0;
|
let mut remain = retval.0;
|
||||||
for (i, buf) in data.iter_mut().enumerate() {
|
for (i, buf) in data.iter_mut().enumerate() {
|
||||||
@ -71,16 +53,15 @@ impl HostSocket {
|
|||||||
&self,
|
&self,
|
||||||
data: &mut [UntrustedSlice],
|
data: &mut [UntrustedSlice],
|
||||||
flags: RecvFlags,
|
flags: RecvFlags,
|
||||||
mut name: Option<&mut [u8]>,
|
|
||||||
mut control: Option<&mut [u8]>,
|
mut control: Option<&mut [u8]>,
|
||||||
) -> Result<(usize, usize, usize, MsgHdrFlags)> {
|
) -> Result<(usize, Option<RawAddr>, MsgFlags, usize)> {
|
||||||
// Prepare the arguments for OCall
|
// Prepare the arguments for OCall
|
||||||
// Host socket fd
|
|
||||||
let host_fd = self.raw_host_fd() as i32;
|
let host_fd = self.raw_host_fd() as i32;
|
||||||
// Name
|
let mut addr = RawAddr::default();
|
||||||
let (msg_name, msg_namelen) = name.as_mut_ptr_and_len();
|
let mut msg_name = addr.as_mut_ptr();
|
||||||
let msg_name = msg_name as *mut c_void;
|
let mut msg_namelen = addr.len();
|
||||||
let mut msg_namelen_recvd = 0_u32;
|
let mut msg_namelen_recvd = 0_u32;
|
||||||
|
|
||||||
// Iovs
|
// Iovs
|
||||||
let mut raw_iovs: Vec<libc::iovec> = data
|
let mut raw_iovs: Vec<libc::iovec> = data
|
||||||
.iter()
|
.iter()
|
||||||
@ -101,7 +82,7 @@ impl HostSocket {
|
|||||||
let status = occlum_ocall_recvmsg(
|
let status = occlum_ocall_recvmsg(
|
||||||
&mut retval as *mut isize,
|
&mut retval as *mut isize,
|
||||||
host_fd,
|
host_fd,
|
||||||
msg_name,
|
msg_name as _,
|
||||||
msg_namelen as u32,
|
msg_namelen as u32,
|
||||||
&mut msg_namelen_recvd as *mut u32,
|
&mut msg_namelen_recvd as *mut u32,
|
||||||
msg_iov,
|
msg_iov,
|
||||||
@ -119,7 +100,7 @@ impl HostSocket {
|
|||||||
retval
|
retval
|
||||||
});
|
});
|
||||||
|
|
||||||
let flags_recvd = MsgHdrFlags::from_bits(msg_flags_recvd).unwrap();
|
let flags_recvd = MsgFlags::from_bits(msg_flags_recvd).unwrap();
|
||||||
|
|
||||||
// Check values returned from outside the enclave
|
// Check values returned from outside the enclave
|
||||||
let bytes_recvd = {
|
let bytes_recvd = {
|
||||||
@ -133,21 +114,24 @@ impl HostSocket {
|
|||||||
// For MSG_TRUNC recvmsg returns the real length of the packet or datagram,
|
// For MSG_TRUNC recvmsg returns the real length of the packet or datagram,
|
||||||
// even when it was longer than the passed buffer.
|
// even when it was longer than the passed buffer.
|
||||||
if flags.contains(RecvFlags::MSG_TRUNC) && retval > max_bytes_recvd {
|
if flags.contains(RecvFlags::MSG_TRUNC) && retval > max_bytes_recvd {
|
||||||
assert!(flags_recvd.contains(MsgHdrFlags::MSG_TRUNC));
|
assert!(flags_recvd.contains(MsgFlags::MSG_TRUNC));
|
||||||
} else {
|
} else {
|
||||||
assert!(retval <= max_bytes_recvd);
|
assert!(retval <= max_bytes_recvd);
|
||||||
}
|
}
|
||||||
retval
|
retval
|
||||||
};
|
};
|
||||||
let msg_namelen_recvd = msg_namelen_recvd as usize;
|
let msg_namelen_recvd = msg_namelen_recvd as usize;
|
||||||
|
|
||||||
|
let raw_addr = if msg_namelen_recvd == 0 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
addr.set_len(msg_namelen_recvd)?;
|
||||||
|
Some(addr)
|
||||||
|
};
|
||||||
|
|
||||||
assert!(msg_namelen_recvd <= msg_namelen);
|
assert!(msg_namelen_recvd <= msg_namelen);
|
||||||
assert!(msg_controllen_recvd <= msg_controllen);
|
assert!(msg_controllen_recvd <= msg_controllen);
|
||||||
Ok((
|
Ok((bytes_recvd, raw_addr, flags_recvd, msg_controllen_recvd))
|
||||||
bytes_recvd,
|
|
||||||
msg_namelen_recvd,
|
|
||||||
msg_controllen_recvd,
|
|
||||||
flags_recvd,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,22 +5,11 @@ impl HostSocket {
|
|||||||
self.sendto(buf, flags, &None)
|
self.sendto(buf, flags, &None)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sendmsg<'a, 'b>(&self, msg: &'b MsgHdr<'a>, flags: SendFlags) -> Result<usize> {
|
pub fn sendmsg(
|
||||||
let msg_iov = msg.get_iovs();
|
|
||||||
|
|
||||||
self.do_sendmsg(
|
|
||||||
msg_iov.as_slices(),
|
|
||||||
flags,
|
|
||||||
msg.get_name(),
|
|
||||||
msg.get_control(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn do_sendmsg(
|
|
||||||
&self,
|
&self,
|
||||||
data: &[&[u8]],
|
data: &[&[u8]],
|
||||||
flags: SendFlags,
|
flags: SendFlags,
|
||||||
name: Option<&[u8]>,
|
addr: &Option<RawAddr>,
|
||||||
control: Option<&[u8]>,
|
control: Option<&[u8]>,
|
||||||
) -> Result<usize> {
|
) -> Result<usize> {
|
||||||
let current = current!();
|
let current = current!();
|
||||||
@ -45,8 +34,8 @@ impl HostSocket {
|
|||||||
bufs
|
bufs
|
||||||
};
|
};
|
||||||
|
|
||||||
let retval = self.do_sendmsg_untrusted_data(&u_data, flags, name, control);
|
let name = addr.as_ref().map(|raw_addr| raw_addr.as_slice());
|
||||||
retval
|
self.do_sendmsg_untrusted_data(&u_data, flags, name, control)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_sendmsg_untrusted_data(
|
fn do_sendmsg_untrusted_data(
|
||||||
|
@ -4,10 +4,11 @@ use std::io::{Read, Seek, SeekFrom, Write};
|
|||||||
use atomic::{Atomic, Ordering};
|
use atomic::{Atomic, Ordering};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::fs::{AccessMode, File, HostFd, IoEvents, StatusFlags, STATUS_FLAGS_MASK};
|
||||||
use crate::fs::{
|
use crate::fs::{
|
||||||
occlum_ocall_ioctl, AccessMode, AtomicIoEvents, CreationFlags, File, FileRef, HostFd, IoEvents,
|
GetIfConf, GetIfReqWithRawCmd, GetReadBufLen, IoctlCmd, NonBuiltinIoctlCmd, SetNonBlocking,
|
||||||
IoctlCmd, StatusFlags, STATUS_FLAGS_MASK,
|
|
||||||
};
|
};
|
||||||
|
use crate::net::socket::sockopt::{GetSockOptRawCmd, SetSockOptRawCmd};
|
||||||
|
|
||||||
//TODO: refactor write syscall to allow zero length with non-zero buffer
|
//TODO: refactor write syscall to allow zero length with non-zero buffer
|
||||||
impl File for HostSocket {
|
impl File for HostSocket {
|
||||||
@ -34,20 +35,46 @@ impl File for HostSocket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn readv(&self, bufs: &mut [&mut [u8]]) -> Result<usize> {
|
fn readv(&self, bufs: &mut [&mut [u8]]) -> Result<usize> {
|
||||||
let (bytes_recvd, _, _, _) = self.do_recvmsg(bufs, RecvFlags::empty(), None, None)?;
|
let (bytes_recvd, _, _, _) = self.recvmsg(bufs, RecvFlags::empty(), None)?;
|
||||||
Ok(bytes_recvd)
|
Ok(bytes_recvd)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn writev(&self, bufs: &[&[u8]]) -> Result<usize> {
|
fn writev(&self, bufs: &[&[u8]]) -> Result<usize> {
|
||||||
self.do_sendmsg(bufs, SendFlags::empty(), None, None)
|
self.sendmsg(bufs, SendFlags::empty(), &None, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn seek(&self, pos: SeekFrom) -> Result<off_t> {
|
fn seek(&self, pos: SeekFrom) -> Result<off_t> {
|
||||||
return_errno!(ESPIPE, "Socket does not support seek")
|
return_errno!(ESPIPE, "Socket does not support seek")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ioctl(&self, cmd: &mut IoctlCmd) -> Result<i32> {
|
fn ioctl(&self, cmd: &mut dyn IoctlCmd) -> Result<()> {
|
||||||
self.ioctl_impl(cmd)
|
match_ioctl_cmd_mut!(&mut *cmd, {
|
||||||
|
cmd: GetSockOptRawCmd => {
|
||||||
|
cmd.execute(self.raw_host_fd())?;
|
||||||
|
},
|
||||||
|
cmd: SetSockOptRawCmd => {
|
||||||
|
cmd.execute(self.raw_host_fd())?;
|
||||||
|
},
|
||||||
|
cmd: GetIfReqWithRawCmd => {
|
||||||
|
cmd.execute(self.raw_host_fd())?;
|
||||||
|
},
|
||||||
|
cmd: GetIfConf => {
|
||||||
|
cmd.execute(self.raw_host_fd())?;
|
||||||
|
},
|
||||||
|
cmd: GetReadBufLen => {
|
||||||
|
cmd.execute(self.raw_host_fd())?;
|
||||||
|
},
|
||||||
|
cmd: SetNonBlocking => {
|
||||||
|
cmd.execute(self.raw_host_fd())?;
|
||||||
|
},
|
||||||
|
cmd: NonBuiltinIoctlCmd => {
|
||||||
|
cmd.execute(self.raw_host_fd())?;
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
return_errno!(EINVAL, "Not supported yet");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn access_mode(&self) -> Result<AccessMode> {
|
fn access_mode(&self) -> Result<AccessMode> {
|
||||||
|
@ -1,354 +0,0 @@
|
|||||||
/// Socket message and its flags.
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
/// C struct for a socket message with const pointers
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
|
||||||
pub struct msghdr {
|
|
||||||
pub msg_name: *const c_void,
|
|
||||||
pub msg_namelen: libc::socklen_t,
|
|
||||||
pub msg_iov: *const libc::iovec,
|
|
||||||
pub msg_iovlen: size_t,
|
|
||||||
pub msg_control: *const c_void,
|
|
||||||
pub msg_controllen: size_t,
|
|
||||||
pub msg_flags: c_int,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
|
||||||
pub struct mmsghdr {
|
|
||||||
pub msg_hdr: msghdr,
|
|
||||||
pub msg_len: c_uint,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// C struct for a socket message with mutable pointers
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
|
||||||
pub struct msghdr_mut {
|
|
||||||
pub msg_name: *mut c_void,
|
|
||||||
pub msg_namelen: libc::socklen_t,
|
|
||||||
pub msg_iov: *mut libc::iovec,
|
|
||||||
pub msg_iovlen: size_t,
|
|
||||||
pub msg_control: *mut c_void,
|
|
||||||
pub msg_controllen: size_t,
|
|
||||||
pub msg_flags: c_int,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// MsgHdr is a memory-safe, immutable wrapper of msghdr
|
|
||||||
pub struct MsgHdr<'a> {
|
|
||||||
name: Option<&'a [u8]>,
|
|
||||||
iovs: Iovs<'a>,
|
|
||||||
control: Option<&'a [u8]>,
|
|
||||||
flags: MsgHdrFlags,
|
|
||||||
c_self: &'a msghdr,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> MsgHdr<'a> {
|
|
||||||
/// Wrap a unsafe msghdr into a safe MsgHdr
|
|
||||||
pub unsafe fn from_c(c_msg: &'a msghdr) -> Result<MsgHdr> {
|
|
||||||
// Convert c_msg's (*mut T, usize)-pair fields to Option<&mut [T]>
|
|
||||||
let name_opt_slice =
|
|
||||||
new_optional_slice(c_msg.msg_name as *const u8, c_msg.msg_namelen as usize);
|
|
||||||
let iovs_opt_slice = new_optional_slice(
|
|
||||||
c_msg.msg_iov as *const libc::iovec,
|
|
||||||
c_msg.msg_iovlen as usize,
|
|
||||||
);
|
|
||||||
let control_opt_slice = new_optional_slice(
|
|
||||||
c_msg.msg_control as *const u8,
|
|
||||||
c_msg.msg_controllen as usize,
|
|
||||||
);
|
|
||||||
|
|
||||||
let flags = MsgHdrFlags::from_bits_truncate(c_msg.msg_flags);
|
|
||||||
|
|
||||||
let iovs = {
|
|
||||||
let iovs_vec = match iovs_opt_slice {
|
|
||||||
Some(iovs_slice) => iovs_slice
|
|
||||||
.iter()
|
|
||||||
.flat_map(|iov| new_optional_slice(iov.iov_base as *const u8, iov.iov_len))
|
|
||||||
.collect(),
|
|
||||||
None => Vec::new(),
|
|
||||||
};
|
|
||||||
Iovs::new(iovs_vec)
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
name: name_opt_slice,
|
|
||||||
iovs: iovs,
|
|
||||||
control: control_opt_slice,
|
|
||||||
flags: flags,
|
|
||||||
c_self: c_msg,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_iovs(&self) -> &Iovs {
|
|
||||||
&self.iovs
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_name(&self) -> Option<&[u8]> {
|
|
||||||
self.name
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_control(&self) -> Option<&[u8]> {
|
|
||||||
self.control
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_flags(&self) -> MsgHdrFlags {
|
|
||||||
self.flags
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// MsgHdrMut is a memory-safe, mutable wrapper of msghdr_mut
|
|
||||||
pub struct MsgHdrMut<'a> {
|
|
||||||
name: Option<&'a mut [u8]>,
|
|
||||||
iovs: IovsMut<'a>,
|
|
||||||
control: Option<&'a mut [u8]>,
|
|
||||||
flags: MsgHdrFlags,
|
|
||||||
c_self: &'a mut msghdr_mut,
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: use macros to eliminate redundant code between MsgHdr and MsgHdrMut
|
|
||||||
impl<'a> MsgHdrMut<'a> {
|
|
||||||
/// Wrap a unsafe msghdr_mut into a safe MsgHdrMut
|
|
||||||
pub unsafe fn from_c(c_msg: &'a mut msghdr_mut) -> Result<MsgHdrMut> {
|
|
||||||
// Convert c_msg's (*mut T, usize)-pair fields to Option<&mut [T]>
|
|
||||||
let name_opt_slice =
|
|
||||||
new_optional_slice_mut(c_msg.msg_name as *mut u8, c_msg.msg_namelen as usize);
|
|
||||||
let iovs_opt_slice =
|
|
||||||
new_optional_slice_mut(c_msg.msg_iov as *mut libc::iovec, c_msg.msg_iovlen as usize);
|
|
||||||
let control_opt_slice =
|
|
||||||
new_optional_slice_mut(c_msg.msg_control as *mut u8, c_msg.msg_controllen as usize);
|
|
||||||
|
|
||||||
let flags = MsgHdrFlags::from_bits_truncate(c_msg.msg_flags);
|
|
||||||
|
|
||||||
let iovs = {
|
|
||||||
let iovs_vec = match iovs_opt_slice {
|
|
||||||
Some(iovs_slice) => iovs_slice
|
|
||||||
.iter()
|
|
||||||
.flat_map(|iov| new_optional_slice_mut(iov.iov_base as *mut u8, iov.iov_len))
|
|
||||||
.collect(),
|
|
||||||
None => Vec::new(),
|
|
||||||
};
|
|
||||||
IovsMut::new(iovs_vec)
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
name: name_opt_slice,
|
|
||||||
iovs: iovs,
|
|
||||||
control: control_opt_slice,
|
|
||||||
flags: flags,
|
|
||||||
c_self: c_msg,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////
|
|
||||||
// Immutable interfaces (same as MsgHdr)
|
|
||||||
/////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
pub fn get_iovs(&self) -> &IovsMut {
|
|
||||||
&self.iovs
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_name(&self) -> Option<&[u8]> {
|
|
||||||
self.name.as_ref().map(|name| &name[..])
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_control(&self) -> Option<&[u8]> {
|
|
||||||
self.control.as_ref().map(|control| &control[..])
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_flags(&self) -> MsgHdrFlags {
|
|
||||||
self.flags
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////
|
|
||||||
// Mutable interfaces (unique to MsgHdrMut)
|
|
||||||
/////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
pub fn get_iovs_mut<'b>(&'b mut self) -> &'b mut IovsMut<'a> {
|
|
||||||
&mut self.iovs
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_name_mut(&mut self) -> Option<&mut [u8]> {
|
|
||||||
self.name.as_mut().map(|name| &mut name[..])
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_name_max_len(&self) -> usize {
|
|
||||||
self.name.as_ref().map(|name| name.len()).unwrap_or(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_name_len(&mut self, new_name_len: usize) -> Result<()> {
|
|
||||||
if new_name_len > self.get_name_max_len() {
|
|
||||||
return_errno!(EINVAL, "new_name_len is too big");
|
|
||||||
}
|
|
||||||
self.c_self.msg_namelen = new_name_len as libc::socklen_t;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_control_mut(&mut self) -> Option<&mut [u8]> {
|
|
||||||
self.control.as_mut().map(|control| &mut control[..])
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_control_max_len(&self) -> usize {
|
|
||||||
self.control
|
|
||||||
.as_ref()
|
|
||||||
.map(|control| control.len())
|
|
||||||
.unwrap_or(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_control_len(&mut self, new_control_len: usize) -> Result<()> {
|
|
||||||
if new_control_len > self.get_control_max_len() {
|
|
||||||
return_errno!(EINVAL, "new_control_len is too big");
|
|
||||||
}
|
|
||||||
self.c_self.msg_controllen = new_control_len;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
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[..]),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_flags(&mut self, flags: MsgHdrFlags) {
|
|
||||||
self.flags = flags;
|
|
||||||
self.c_self.msg_flags = flags.bits();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This struct is used to iterate through the control messages.
|
|
||||||
///
|
|
||||||
/// `cmsghdr` is a C struct for ancillary data object information of a unix socket.
|
|
||||||
pub struct CMessages<'a> {
|
|
||||||
buffer: &'a [u8],
|
|
||||||
current: Option<&'a libc::cmsghdr>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for CMessages<'a> {
|
|
||||||
type Item = CmsgData<'a>;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
let cmsg = unsafe {
|
|
||||||
let mut msg: libc::msghdr = core::mem::zeroed();
|
|
||||||
msg.msg_control = self.buffer.as_ptr() as *mut _;
|
|
||||||
msg.msg_controllen = self.buffer.len() as _;
|
|
||||||
|
|
||||||
let cmsg = if let Some(current) = self.current {
|
|
||||||
libc::CMSG_NXTHDR(&msg, current)
|
|
||||||
} else {
|
|
||||||
libc::CMSG_FIRSTHDR(&msg)
|
|
||||||
};
|
|
||||||
cmsg.as_ref()?
|
|
||||||
};
|
|
||||||
|
|
||||||
self.current = Some(cmsg);
|
|
||||||
CmsgData::try_from_cmsghdr(cmsg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> CMessages<'a> {
|
|
||||||
pub fn from_bytes(msg_control: &'a mut [u8]) -> Self {
|
|
||||||
Self {
|
|
||||||
buffer: msg_control,
|
|
||||||
current: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Control message data of variable type. The data resides next to `cmsghdr`.
|
|
||||||
pub enum CmsgData<'a> {
|
|
||||||
ScmRights(ScmRights<'a>),
|
|
||||||
ScmCredentials,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> CmsgData<'a> {
|
|
||||||
/// Create an `CmsgData::ScmRights` variant.
|
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// `data` must contain a valid control message and the control message must be type of
|
|
||||||
/// `SOL_SOCKET` and level of `SCM_RIGHTS`.
|
|
||||||
unsafe fn as_rights(data: &'a mut [u8]) -> Self {
|
|
||||||
let scm_rights = ScmRights { data };
|
|
||||||
CmsgData::ScmRights(scm_rights)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create an `CmsgData::ScmCredentials` variant.
|
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// `data` must contain a valid control message and the control message must be type of
|
|
||||||
/// `SOL_SOCKET` and level of `SCM_CREDENTIALS`.
|
|
||||||
unsafe fn as_credentials(_data: &'a [u8]) -> Self {
|
|
||||||
CmsgData::ScmCredentials
|
|
||||||
}
|
|
||||||
|
|
||||||
fn try_from_cmsghdr(cmsg: &'a libc::cmsghdr) -> Option<Self> {
|
|
||||||
unsafe {
|
|
||||||
let cmsg_len_zero = libc::CMSG_LEN(0) as usize;
|
|
||||||
let data_len = (*cmsg).cmsg_len as usize - cmsg_len_zero;
|
|
||||||
let data = libc::CMSG_DATA(cmsg);
|
|
||||||
let data = core::slice::from_raw_parts_mut(data, data_len);
|
|
||||||
|
|
||||||
match (*cmsg).cmsg_level {
|
|
||||||
libc::SOL_SOCKET => match (*cmsg).cmsg_type {
|
|
||||||
libc::SCM_RIGHTS => Some(CmsgData::as_rights(data)),
|
|
||||||
libc::SCM_CREDENTIALS => Some(CmsgData::as_credentials(data)),
|
|
||||||
_ => None,
|
|
||||||
},
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The data unit of this control message is file descriptor(s).
|
|
||||||
///
|
|
||||||
/// The level is equal to `SOL_SOCKET` and the type is equal to `SCM_RIGHTS`.
|
|
||||||
pub struct ScmRights<'a> {
|
|
||||||
data: &'a mut [u8],
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> ScmRights<'a> {
|
|
||||||
/// Iterate and reassign each fd in data buffer, given a reassignment function.
|
|
||||||
pub fn iter_and_reassign_fds<F>(&mut self, reassign_fd_fn: F)
|
|
||||||
where
|
|
||||||
F: Fn(FileDesc) -> FileDesc,
|
|
||||||
{
|
|
||||||
for fd_bytes in self.data.chunks_exact_mut(core::mem::size_of::<FileDesc>()) {
|
|
||||||
let old_fd = FileDesc::from_ne_bytes(fd_bytes.try_into().unwrap());
|
|
||||||
let reassigned_fd = reassign_fd_fn(old_fd);
|
|
||||||
fd_bytes.copy_from_slice(&reassigned_fd.to_ne_bytes());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn iter_fds(&self) -> impl Iterator<Item = FileDesc> + '_ {
|
|
||||||
self.data
|
|
||||||
.chunks_exact(core::mem::size_of::<FileDesc>())
|
|
||||||
.map(|fd_bytes| FileDesc::from_ne_bytes(fd_bytes.try_into().unwrap()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn new_optional_slice<'a, T>(slice_ptr: *const T, slice_size: usize) -> Option<&'a [T]> {
|
|
||||||
if !slice_ptr.is_null() {
|
|
||||||
let slice = core::slice::from_raw_parts::<T>(slice_ptr, slice_size);
|
|
||||||
Some(slice)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn new_optional_slice_mut<'a, T>(
|
|
||||||
slice_ptr: *mut T,
|
|
||||||
slice_size: usize,
|
|
||||||
) -> Option<&'a mut [T]> {
|
|
||||||
if !slice_ptr.is_null() {
|
|
||||||
let slice = core::slice::from_raw_parts_mut::<T>(slice_ptr, slice_size);
|
|
||||||
Some(slice)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
use super::*;
|
|
||||||
|
|
||||||
bitflags! {
|
|
||||||
pub struct HowToShut: c_int {
|
|
||||||
const READ = 0;
|
|
||||||
const WRITE = 1;
|
|
||||||
const BOTH = 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HowToShut {
|
|
||||||
pub fn try_from_raw(how: c_int) -> Result<Self> {
|
|
||||||
match how {
|
|
||||||
0 => Ok(Self::READ),
|
|
||||||
1 => Ok(Self::WRITE),
|
|
||||||
2 => Ok(Self::BOTH),
|
|
||||||
_ => return_errno!(EINVAL, "invalid how"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_shut_read(&self) -> bool {
|
|
||||||
*self == Self::READ || *self == Self::BOTH
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_shut_write(&self) -> bool {
|
|
||||||
*self == Self::WRITE || *self == Self::BOTH
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
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,156 +0,0 @@
|
|||||||
use super::*;
|
|
||||||
use std::path::{Path, PathBuf};
|
|
||||||
use std::{cmp, mem, slice, str};
|
|
||||||
|
|
||||||
const MAX_PATH_LEN: usize = 108;
|
|
||||||
const SUN_FAMILY_LEN: usize = mem::size_of::<libc::sa_family_t>();
|
|
||||||
lazy_static! {
|
|
||||||
static ref SUN_PATH_OFFSET: usize = memoffset::offset_of!(libc::sockaddr_un, sun_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
||||||
pub enum Addr {
|
|
||||||
File(Option<usize>, UnixPath), // An optional inode number and path. Use inode if there is one.
|
|
||||||
Abstract(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Addr {
|
|
||||||
/// Caller should guarentee the sockaddr and addr_len are valid.
|
|
||||||
/// The pathname should end with a '\0' within the passed length.
|
|
||||||
/// The abstract name should both start and end with a '\0' within the passed length.
|
|
||||||
pub unsafe fn try_from_raw(
|
|
||||||
sockaddr: *const libc::sockaddr,
|
|
||||||
addr_len: libc::socklen_t,
|
|
||||||
) -> Result<Self> {
|
|
||||||
let addr_len = addr_len as usize;
|
|
||||||
|
|
||||||
// TODO: support autobind to validate when addr_len == SUN_FAMILY_LEN
|
|
||||||
if addr_len <= SUN_FAMILY_LEN {
|
|
||||||
return_errno!(EINVAL, "the address is too short.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if addr_len > MAX_PATH_LEN + *SUN_PATH_OFFSET {
|
|
||||||
return_errno!(EINVAL, "the address is too long.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if AddressFamily::try_from((*sockaddr).sa_family)? != AddressFamily::LOCAL {
|
|
||||||
return_errno!(EINVAL, "not a valid address for unix socket");
|
|
||||||
}
|
|
||||||
|
|
||||||
let sockaddr = sockaddr as *const libc::sockaddr_un;
|
|
||||||
let sun_path = (*sockaddr).sun_path;
|
|
||||||
|
|
||||||
if sun_path[0] == 0 {
|
|
||||||
let path_ptr = sun_path[1..(addr_len - *SUN_PATH_OFFSET)].as_ptr();
|
|
||||||
let path_slice =
|
|
||||||
slice::from_raw_parts(path_ptr as *const u8, addr_len - *SUN_PATH_OFFSET - 1);
|
|
||||||
|
|
||||||
Ok(Self::Abstract(
|
|
||||||
str::from_utf8(&path_slice).unwrap().to_string(),
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
let path_cstr = CStr::from_ptr(sun_path.as_ptr());
|
|
||||||
if path_cstr.to_bytes_with_nul().len() > MAX_PATH_LEN {
|
|
||||||
return_errno!(EINVAL, "no null in the address");
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Self::File(None, UnixPath::new(path_cstr.to_str().unwrap())))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn copy_to_slice(&self, dst: &mut [u8]) -> usize {
|
|
||||||
let (raw_addr, addr_len) = self.to_raw();
|
|
||||||
let src =
|
|
||||||
unsafe { std::slice::from_raw_parts(&raw_addr as *const _ as *const u8, addr_len) };
|
|
||||||
let copied = std::cmp::min(dst.len(), addr_len);
|
|
||||||
dst[..copied].copy_from_slice(&src[..copied]);
|
|
||||||
copied
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn raw_len(&self) -> usize {
|
|
||||||
/// The '/0' at the end of Self::File counts
|
|
||||||
self.path_str().len()
|
|
||||||
+ 1
|
|
||||||
+ *SUN_PATH_OFFSET
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn path_str(&self) -> &str {
|
|
||||||
match self {
|
|
||||||
Self::File(_, unix_path) => &unix_path.path_str(),
|
|
||||||
Self::Abstract(path) => &path,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_raw(&self) -> (libc::sockaddr_un, usize) {
|
|
||||||
let mut addr: libc::sockaddr_un = unsafe { mem::zeroed() };
|
|
||||||
addr.sun_family = AddressFamily::LOCAL as libc::sa_family_t;
|
|
||||||
|
|
||||||
let addr_len = match self {
|
|
||||||
Self::File(_, unix_path) => {
|
|
||||||
let path_str = unix_path.path_str();
|
|
||||||
let buf_len = path_str.len();
|
|
||||||
/// addr is initialized to all zeros and try_from_raw guarentees
|
|
||||||
/// unix_path length is shorter than sun_path, so sun_path here
|
|
||||||
/// will always have a null terminator
|
|
||||||
addr.sun_path[..buf_len]
|
|
||||||
.copy_from_slice(unsafe { &*(path_str.as_bytes() as *const _ as *const [i8]) });
|
|
||||||
buf_len + *SUN_PATH_OFFSET + 1
|
|
||||||
}
|
|
||||||
Self::Abstract(path_str) => {
|
|
||||||
addr.sun_path[0] = 0;
|
|
||||||
let buf_len = path_str.len() + 1;
|
|
||||||
addr.sun_path[1..buf_len]
|
|
||||||
.copy_from_slice(unsafe { &*(path_str.as_bytes() as *const _ as *const [i8]) });
|
|
||||||
buf_len + *SUN_PATH_OFFSET
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
(addr, addr_len)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
||||||
pub struct UnixPath {
|
|
||||||
inner: PathBuf,
|
|
||||||
/// Holds the cwd when a relative path is created
|
|
||||||
cwd: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl UnixPath {
|
|
||||||
pub fn new(path: &str) -> Self {
|
|
||||||
let inner = PathBuf::from(path);
|
|
||||||
let is_absolute = inner.is_absolute();
|
|
||||||
Self {
|
|
||||||
inner: inner,
|
|
||||||
cwd: if is_absolute {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
let thread = current!();
|
|
||||||
let fs = thread.fs().read().unwrap();
|
|
||||||
let cwd = fs.cwd().to_owned();
|
|
||||||
|
|
||||||
Some(cwd)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn absolute(&self) -> String {
|
|
||||||
let path_str = self.path_str();
|
|
||||||
if self.inner.is_absolute() {
|
|
||||||
path_str.to_string()
|
|
||||||
} else {
|
|
||||||
let mut prefix = self.cwd.as_ref().unwrap().clone();
|
|
||||||
if prefix.ends_with("/") {
|
|
||||||
prefix.push_str(path_str);
|
|
||||||
} else {
|
|
||||||
prefix.push_str("/");
|
|
||||||
prefix.push_str(path_str);
|
|
||||||
}
|
|
||||||
prefix
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn path_str(&self) -> &str {
|
|
||||||
self.inner.to_str().unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,19 +1,16 @@
|
|||||||
use self::addr::Addr;
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
mod addr;
|
|
||||||
mod stream;
|
mod stream;
|
||||||
|
|
||||||
pub use self::addr::Addr as UnixAddr;
|
|
||||||
pub use self::stream::Stream;
|
pub use self::stream::Stream;
|
||||||
|
|
||||||
//TODO: rewrite this file when a new kind of uds is added
|
//TODO: rewrite this file when a new kind of uds is added
|
||||||
pub fn unix_socket(socket_type: SocketType, flags: FileFlags, protocol: i32) -> Result<Stream> {
|
pub fn unix_socket(socket_type: Type, flags: SocketFlags, protocol: i32) -> Result<Stream> {
|
||||||
if protocol != 0 && protocol != AddressFamily::LOCAL as i32 {
|
if protocol != 0 && protocol != Domain::LOCAL as i32 {
|
||||||
return_errno!(EPROTONOSUPPORT, "protocol is not supported");
|
return_errno!(EPROTONOSUPPORT, "protocol is not supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
if socket_type == SocketType::STREAM {
|
if socket_type == Type::STREAM {
|
||||||
Ok(Stream::new(flags))
|
Ok(Stream::new(flags))
|
||||||
} else {
|
} else {
|
||||||
return_errno!(ESOCKTNOSUPPORT, "only stream type is supported");
|
return_errno!(ESOCKTNOSUPPORT, "only stream type is supported");
|
||||||
@ -21,15 +18,15 @@ pub fn unix_socket(socket_type: SocketType, flags: FileFlags, protocol: i32) ->
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn socketpair(
|
pub fn socketpair(
|
||||||
socket_type: SocketType,
|
socket_type: Type,
|
||||||
flags: FileFlags,
|
flags: SocketFlags,
|
||||||
protocol: i32,
|
protocol: i32,
|
||||||
) -> Result<(Stream, Stream)> {
|
) -> Result<(Stream, Stream)> {
|
||||||
if protocol != 0 && protocol != AddressFamily::LOCAL as i32 {
|
if protocol != 0 && protocol != Domain::LOCAL as i32 {
|
||||||
return_errno!(EPROTONOSUPPORT, "protocol is not supported");
|
return_errno!(EPROTONOSUPPORT, "protocol is not supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
if socket_type == SocketType::STREAM {
|
if socket_type == Type::STREAM {
|
||||||
Stream::socketpair(flags)
|
Stream::socketpair(flags)
|
||||||
} else {
|
} else {
|
||||||
return_errno!(ESOCKTNOSUPPORT, "only stream type is supported");
|
return_errno!(ESOCKTNOSUPPORT, "only stream type is supported");
|
||||||
|
@ -39,9 +39,9 @@ impl AddressSpace {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_binder(&self, addr: &Addr) -> Result<()> {
|
pub fn add_binder(&self, addr: &UnixAddr) -> Result<()> {
|
||||||
let key = Self::get_key(addr).ok_or_else(|| errno!(EINVAL, "can't find socket file"))?;
|
let key = Self::get_key(addr).ok_or_else(|| errno!(EINVAL, "can't find socket file"))?;
|
||||||
let mut space = self.get_space(addr);
|
let mut space = self.get_space(addr)?;
|
||||||
if space.contains_key(&key) {
|
if space.contains_key(&key) {
|
||||||
return_errno!(EADDRINUSE, "the addr is already bound");
|
return_errno!(EADDRINUSE, "the addr is already bound");
|
||||||
} else {
|
} else {
|
||||||
@ -52,13 +52,13 @@ impl AddressSpace {
|
|||||||
|
|
||||||
pub(super) fn add_listener(
|
pub(super) fn add_listener(
|
||||||
&self,
|
&self,
|
||||||
addr: &Addr,
|
addr: &UnixAddr,
|
||||||
capacity: usize,
|
capacity: usize,
|
||||||
nonblocking: bool,
|
nonblocking: bool,
|
||||||
notifier: Arc<RelayNotifier>,
|
notifier: Arc<RelayNotifier>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let key = Self::get_key(addr).ok_or_else(|| errno!(EINVAL, "the socket is not bound"))?;
|
let key = Self::get_key(addr).ok_or_else(|| errno!(EINVAL, "the socket is not bound"))?;
|
||||||
let mut space = self.get_space(addr);
|
let mut space = self.get_space(addr)?;
|
||||||
|
|
||||||
if let Some(option) = space.get(&key) {
|
if let Some(option) = space.get(&key) {
|
||||||
if option.is_none() {
|
if option.is_none() {
|
||||||
@ -75,9 +75,9 @@ impl AddressSpace {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resize_listener(&self, addr: &Addr, capacity: usize) -> Result<()> {
|
pub fn resize_listener(&self, addr: &UnixAddr, capacity: usize) -> Result<()> {
|
||||||
let key = Self::get_key(addr).ok_or_else(|| errno!(EINVAL, "the socket is not bound"))?;
|
let key = Self::get_key(addr).ok_or_else(|| errno!(EINVAL, "the socket is not bound"))?;
|
||||||
let mut space = self.get_space(addr);
|
let mut space = self.get_space(addr)?;
|
||||||
|
|
||||||
if let Some(option) = space.get(&key) {
|
if let Some(option) = space.get(&key) {
|
||||||
if let Some(listener) = option {
|
if let Some(listener) = option {
|
||||||
@ -91,33 +91,33 @@ impl AddressSpace {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_incoming(&self, addr: &Addr, sock: Endpoint) -> Result<()> {
|
pub fn push_incoming(&self, addr: &UnixAddr, sock: Endpoint) -> Result<()> {
|
||||||
self.get_listener_ref(addr)
|
self.get_listener_ref(addr)
|
||||||
.ok_or_else(|| errno!(ECONNREFUSED, "no one's listening on the remote address"))?
|
.ok_or_else(|| errno!(ECONNREFUSED, "no one's listening on the remote address"))?
|
||||||
.push_incoming(sock)
|
.push_incoming(sock)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pop_incoming(&self, addr: &Addr) -> Result<Endpoint> {
|
pub fn pop_incoming(&self, addr: &UnixAddr) -> Result<Endpoint> {
|
||||||
self.get_listener_ref(addr)
|
self.get_listener_ref(addr)
|
||||||
.ok_or_else(|| errno!(EINVAL, "the socket is not listening"))?
|
.ok_or_else(|| errno!(EINVAL, "the socket is not listening"))?
|
||||||
.pop_incoming()
|
.pop_incoming()
|
||||||
.ok_or_else(|| errno!(EAGAIN, "No connection is incoming"))
|
.ok_or_else(|| errno!(EAGAIN, "No connection is incoming"))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_listener_ref(&self, addr: &Addr) -> Option<Arc<Listener>> {
|
pub fn get_listener_ref(&self, addr: &UnixAddr) -> Option<Arc<Listener>> {
|
||||||
let key = Self::get_key(addr);
|
let key = Self::get_key(addr);
|
||||||
if let Some(key) = key {
|
if let Some(key) = key {
|
||||||
let space = self.get_space(addr);
|
let space = self.get_space(addr).unwrap();
|
||||||
space.get(&key).map(|x| x.clone()).flatten()
|
space.get(&key).map(|x| x.clone()).flatten()
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_addr(&self, addr: &Addr) {
|
pub fn remove_addr(&self, addr: &UnixAddr) {
|
||||||
let key = Self::get_key(addr);
|
let key = Self::get_key(addr);
|
||||||
if let Some(key) = key {
|
if let Some(key) = key {
|
||||||
let mut space = self.get_space(addr);
|
let mut space = self.get_space(addr).unwrap();
|
||||||
space.remove(&key);
|
space.remove(&key);
|
||||||
} else {
|
} else {
|
||||||
warn!("address space key not exit: {:?}", addr);
|
warn!("address space key not exit: {:?}", addr);
|
||||||
@ -126,21 +126,22 @@ impl AddressSpace {
|
|||||||
|
|
||||||
fn get_space(
|
fn get_space(
|
||||||
&self,
|
&self,
|
||||||
addr: &Addr,
|
addr: &UnixAddr,
|
||||||
) -> SgxMutexGuard<'_, BTreeMap<AddressSpaceKey, Option<Arc<Listener>>>> {
|
) -> Result<SgxMutexGuard<'_, BTreeMap<AddressSpaceKey, Option<Arc<Listener>>>>> {
|
||||||
match addr {
|
match addr {
|
||||||
Addr::File(_, _) => self.file.lock().unwrap(),
|
UnixAddr::File(_, _) => Ok(self.file.lock().unwrap()),
|
||||||
Addr::Abstract(_) => self.abstr.lock().unwrap(),
|
UnixAddr::Abstract(_) => Ok(self.abstr.lock().unwrap()),
|
||||||
|
UnixAddr::Unnamed => return_errno!(EINVAL, "can't get path name for unnamed socket"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_key(addr: &Addr) -> Option<AddressSpaceKey> {
|
fn get_key(addr: &UnixAddr) -> Option<AddressSpaceKey> {
|
||||||
trace!("addr = {:?}", addr);
|
trace!("addr = {:?}", addr);
|
||||||
match addr {
|
match addr {
|
||||||
Addr::File(inode_num, unix_path) if inode_num.is_some() => {
|
UnixAddr::File(inode_num, unix_path) if inode_num.is_some() => {
|
||||||
Some(AddressSpaceKey::from_inode(inode_num.unwrap()))
|
Some(AddressSpaceKey::from_inode(inode_num.unwrap()))
|
||||||
}
|
}
|
||||||
Addr::File(_, unix_path) => {
|
UnixAddr::File(_, unix_path) => {
|
||||||
let inode = {
|
let inode = {
|
||||||
let file_path = unix_path.absolute();
|
let file_path = unix_path.absolute();
|
||||||
let current = current!();
|
let current = current!();
|
||||||
@ -153,7 +154,10 @@ impl AddressSpace {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Addr::Abstract(path) => Some(AddressSpaceKey::from_path(addr.path_str().to_string())),
|
UnixAddr::Abstract(path) => Some(AddressSpaceKey::from_path(
|
||||||
|
addr.path_str().unwrap().to_string(),
|
||||||
|
)),
|
||||||
|
UnixAddr::Unnamed => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ pub fn end_pair(nonblocking: bool) -> Result<(Endpoint, Endpoint)> {
|
|||||||
|
|
||||||
/// One end of the connected unix socket
|
/// One end of the connected unix socket
|
||||||
pub struct Inner {
|
pub struct Inner {
|
||||||
addr: RwLock<Option<Addr>>,
|
addr: RwLock<Option<UnixAddr>>,
|
||||||
reader: Consumer<u8>,
|
reader: Consumer<u8>,
|
||||||
writer: Producer<u8>,
|
writer: Producer<u8>,
|
||||||
peer: Weak<Self>,
|
peer: Weak<Self>,
|
||||||
@ -47,15 +47,15 @@ pub struct Inner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Inner {
|
impl Inner {
|
||||||
pub fn addr(&self) -> Option<Addr> {
|
pub fn addr(&self) -> Option<UnixAddr> {
|
||||||
self.addr.read().unwrap().clone()
|
self.addr.read().unwrap().clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_addr(&self, addr: &Addr) {
|
pub fn set_addr(&self, addr: &UnixAddr) {
|
||||||
*self.addr.write().unwrap() = Some(addr.clone());
|
*self.addr.write().unwrap() = Some(addr.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn peer_addr(&self) -> Option<Addr> {
|
pub fn peer_addr(&self) -> Option<UnixAddr> {
|
||||||
self.peer.upgrade().map(|end| end.addr().clone()).flatten()
|
self.peer.upgrade().map(|end| end.addr().clone()).flatten()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,16 +90,16 @@ impl Inner {
|
|||||||
self.reader.items_to_consume()
|
self.reader.items_to_consume()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn shutdown(&self, how: HowToShut) -> Result<()> {
|
pub fn shutdown(&self, how: Shutdown) -> Result<()> {
|
||||||
if !self.is_connected() {
|
if !self.is_connected() {
|
||||||
return_errno!(ENOTCONN, "The socket is not connected.");
|
return_errno!(ENOTCONN, "The socket is not connected.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if how.to_shut_read() {
|
if how.should_shut_read() {
|
||||||
self.reader.shutdown()
|
self.reader.shutdown()
|
||||||
}
|
}
|
||||||
|
|
||||||
if how.to_shut_write() {
|
if how.should_shut_write() {
|
||||||
self.writer.shutdown()
|
self.writer.shutdown()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
use super::address_space::ADDRESS_SPACE;
|
use super::address_space::ADDRESS_SPACE;
|
||||||
use super::stream::Status;
|
use super::stream::Status;
|
||||||
use super::*;
|
use super::*;
|
||||||
use fs::{AccessMode, File, FileRef, IoEvents, IoNotifier, IoctlCmd, StatusFlags};
|
use fs::{AccessMode, File, IoEvents, IoNotifier, StatusFlags};
|
||||||
use rcore_fs::vfs::{FileType, Metadata, Timespec};
|
use rcore_fs::vfs::{FileType, Metadata, Timespec};
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
|
|
||||||
|
use crate::fs::{GetReadBufLen, IoctlCmd, SetNonBlocking};
|
||||||
|
|
||||||
impl File for Stream {
|
impl File for Stream {
|
||||||
fn read(&self, buf: &mut [u8]) -> Result<usize> {
|
fn read(&self, buf: &mut [u8]) -> Result<usize> {
|
||||||
// The connected status will not be changed any more
|
// The connected status will not be changed any more
|
||||||
@ -55,23 +57,23 @@ impl File for Stream {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ioctl(&self, cmd: &mut IoctlCmd) -> Result<i32> {
|
fn ioctl(&self, cmd: &mut dyn IoctlCmd) -> Result<()> {
|
||||||
match cmd {
|
match_ioctl_cmd_auto_error!(cmd, {
|
||||||
IoctlCmd::TCGETS(_) => return_errno!(ENOTTY, "not tty device"),
|
cmd : GetReadBufLen => {
|
||||||
IoctlCmd::TCSETS(_) => return_errno!(ENOTTY, "not tty device"),
|
match &*self.inner() {
|
||||||
IoctlCmd::FIONBIO(nonblocking) => {
|
|
||||||
self.set_nonblocking(**nonblocking != 0);
|
|
||||||
}
|
|
||||||
IoctlCmd::FIONREAD(arg) => match &*self.inner() {
|
|
||||||
Status::Connected(endpoint) => {
|
Status::Connected(endpoint) => {
|
||||||
let bytes_to_read = endpoint.bytes_to_read().min(std::i32::MAX as usize) as i32;
|
let bytes_to_read = endpoint.bytes_to_read().min(std::i32::MAX as usize) as i32;
|
||||||
**arg = bytes_to_read;
|
cmd.set_output(bytes_to_read as _);
|
||||||
}
|
}
|
||||||
_ => return_errno!(ENOTCONN, "unconnected socket"),
|
_ => return_errno!(ENOTCONN, "unconnected socket"),
|
||||||
|
};
|
||||||
},
|
},
|
||||||
_ => return_errno!(EINVAL, "unknown ioctl cmd for unix socket"),
|
cmd : SetNonBlocking => {
|
||||||
|
let nonblocking = cmd.input();
|
||||||
|
self.set_nonblocking(*nonblocking != 0);
|
||||||
}
|
}
|
||||||
Ok(0)
|
});
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn access_mode(&self) -> Result<AccessMode> {
|
fn access_mode(&self) -> Result<AccessMode> {
|
||||||
|
@ -5,7 +5,7 @@ use events::{Event, EventFilter, Notifier, Observer};
|
|||||||
use fs::channel::Channel;
|
use fs::channel::Channel;
|
||||||
use fs::IoEvents;
|
use fs::IoEvents;
|
||||||
use fs::{CreationFlags, FileMode};
|
use fs::{CreationFlags, FileMode};
|
||||||
use net::socket::{CMessages, CmsgData, Iovs, MsgHdr, MsgHdrMut};
|
use net::socket::{CMessages, CmsgData};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@ -23,17 +23,17 @@ pub struct Stream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Stream {
|
impl Stream {
|
||||||
pub fn new(flags: FileFlags) -> Self {
|
pub fn new(flags: SocketFlags) -> Self {
|
||||||
Self {
|
Self {
|
||||||
inner: SgxMutex::new(Status::Idle(Info::new(
|
inner: SgxMutex::new(Status::Idle(Info::new(
|
||||||
flags.contains(FileFlags::SOCK_NONBLOCK),
|
flags.contains(SocketFlags::SOCK_NONBLOCK),
|
||||||
))),
|
))),
|
||||||
notifier: Arc::new(RelayNotifier::new()),
|
notifier: Arc::new(RelayNotifier::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn socketpair(flags: FileFlags) -> Result<(Self, Self)> {
|
pub fn socketpair(flags: SocketFlags) -> Result<(Self, Self)> {
|
||||||
let nonblocking = flags.contains(FileFlags::SOCK_NONBLOCK);
|
let nonblocking = flags.contains(SocketFlags::SOCK_NONBLOCK);
|
||||||
let (end_a, end_b) = end_pair(nonblocking)?;
|
let (end_a, end_b) = end_pair(nonblocking)?;
|
||||||
let notifier_a = Arc::new(RelayNotifier::new());
|
let notifier_a = Arc::new(RelayNotifier::new());
|
||||||
let notifier_b = Arc::new(RelayNotifier::new());
|
let notifier_b = Arc::new(RelayNotifier::new());
|
||||||
@ -53,15 +53,17 @@ impl Stream {
|
|||||||
Ok((socket_a, socket_b))
|
Ok((socket_a, socket_b))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn addr(&self) -> Option<Addr> {
|
pub fn addr(&self) -> UnixAddr {
|
||||||
match &*self.inner() {
|
let addr_opt = match &*self.inner() {
|
||||||
Status::Idle(info) => info.addr().clone(),
|
Status::Idle(info) => info.addr().clone(),
|
||||||
Status::Connected(endpoint) => endpoint.addr(),
|
Status::Connected(endpoint) => endpoint.addr(),
|
||||||
Status::Listening(addr) => Some(addr).cloned(),
|
Status::Listening(addr) => Some(addr).cloned(),
|
||||||
}
|
};
|
||||||
|
|
||||||
|
addr_opt.unwrap_or(UnixAddr::Unnamed)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn peer_addr(&self) -> Result<Addr> {
|
pub fn peer_addr(&self) -> Result<UnixAddr> {
|
||||||
if let Status::Connected(endpoint) = &*self.inner() {
|
if let Status::Connected(endpoint) = &*self.inner() {
|
||||||
if let Some(addr) = endpoint.peer_addr() {
|
if let Some(addr) = endpoint.peer_addr() {
|
||||||
return Ok(addr);
|
return Ok(addr);
|
||||||
@ -70,8 +72,8 @@ impl Stream {
|
|||||||
return_errno!(ENOTCONN, "the socket is not connected");
|
return_errno!(ENOTCONN, "the socket is not connected");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bind(&self, addr: &mut Addr) -> Result<()> {
|
pub fn bind(&self, addr: &mut UnixAddr) -> Result<()> {
|
||||||
if let Addr::File(inode_num, path) = addr {
|
if let UnixAddr::File(inode_num, path) = addr {
|
||||||
// create the corresponding file in the fs and fill Addr with its inode
|
// create the corresponding file in the fs and fill Addr with its inode
|
||||||
let corresponding_inode_num = {
|
let corresponding_inode_num = {
|
||||||
let current = current!();
|
let current = current!();
|
||||||
@ -143,7 +145,7 @@ impl Stream {
|
|||||||
|
|
||||||
/// The establishment of the connection is very fast and can be done immediately.
|
/// The establishment of the connection is very fast and can be done immediately.
|
||||||
/// Therefore, the connect function in our implementation will never block.
|
/// Therefore, the connect function in our implementation will never block.
|
||||||
pub fn connect(&self, addr: &Addr) -> Result<()> {
|
pub fn connect(&self, addr: &UnixAddr) -> Result<()> {
|
||||||
debug!("connect to {:?}", addr);
|
debug!("connect to {:?}", addr);
|
||||||
|
|
||||||
let mut inner = self.inner();
|
let mut inner = self.inner();
|
||||||
@ -168,7 +170,7 @@ impl Stream {
|
|||||||
ADDRESS_SPACE
|
ADDRESS_SPACE
|
||||||
.push_incoming(addr, end_incoming)
|
.push_incoming(addr, end_incoming)
|
||||||
.map_err(|e| match e.errno() {
|
.map_err(|e| match e.errno() {
|
||||||
Errno::EAGAIN => errno!(ECONNREFUSED, "the backlog is full"),
|
EAGAIN => errno!(ECONNREFUSED, "the backlog is full"),
|
||||||
_ => e,
|
_ => e,
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
@ -187,12 +189,12 @@ impl Stream {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn accept(&self, flags: FileFlags) -> Result<(Self, Option<Addr>)> {
|
pub fn accept(&self, flags: SocketFlags) -> Result<(Self, Option<UnixAddr>)> {
|
||||||
let status = (*self.inner()).clone();
|
let status = (*self.inner()).clone();
|
||||||
match status {
|
match status {
|
||||||
Status::Listening(addr) => {
|
Status::Listening(addr) => {
|
||||||
let endpoint = ADDRESS_SPACE.pop_incoming(&addr)?;
|
let endpoint = ADDRESS_SPACE.pop_incoming(&addr)?;
|
||||||
endpoint.set_nonblocking(flags.contains(FileFlags::SOCK_NONBLOCK));
|
endpoint.set_nonblocking(flags.contains(SocketFlags::SOCK_NONBLOCK));
|
||||||
endpoint.set_ancillary(Ancillary {
|
endpoint.set_ancillary(Ancillary {
|
||||||
tid: current!().tid(),
|
tid: current!().tid(),
|
||||||
});
|
});
|
||||||
@ -216,12 +218,12 @@ impl Stream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: handle flags
|
// TODO: handle flags
|
||||||
pub fn sendto(&self, buf: &[u8], flags: SendFlags, addr: &Option<Addr>) -> Result<usize> {
|
pub fn sendto(&self, buf: &[u8], flags: SendFlags, addr: &Option<UnixAddr>) -> Result<usize> {
|
||||||
self.write(buf)
|
self.write(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: handle flags
|
// TODO: handle flags
|
||||||
pub fn recvfrom(&self, buf: &mut [u8], flags: RecvFlags) -> Result<(usize, Option<Addr>)> {
|
pub fn recvfrom(&self, buf: &mut [u8], flags: RecvFlags) -> Result<(usize, Option<UnixAddr>)> {
|
||||||
let data_len = self.read(buf)?;
|
let data_len = self.read(buf)?;
|
||||||
let addr = self.peer_addr().ok();
|
let addr = self.peer_addr().ok();
|
||||||
|
|
||||||
@ -230,33 +232,39 @@ impl Stream {
|
|||||||
Ok((data_len, addr))
|
Ok((data_len, addr))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sendmsg(&self, msg_hdr: &MsgHdr, flags: SendFlags) -> Result<usize> {
|
pub fn sendmsg(
|
||||||
|
&self,
|
||||||
|
bufs: &[&[u8]],
|
||||||
|
flags: SendFlags,
|
||||||
|
control: Option<&[u8]>,
|
||||||
|
) -> Result<usize> {
|
||||||
if !flags.is_empty() {
|
if !flags.is_empty() {
|
||||||
warn!("unsupported flags: {:?}", flags);
|
warn!("unsupported flags: {:?}", flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
let bufs = msg_hdr.get_iovs().as_slices();
|
let data_len = self.writev(bufs)?;
|
||||||
let mut data_len = self.writev(bufs)?;
|
if let Some(msg_control) = control {
|
||||||
|
self.write(msg_control)?;
|
||||||
if let Some(msg_control) = msg_hdr.get_control() {
|
|
||||||
data_len += self.write(msg_control)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(data_len)
|
Ok(data_len)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn recvmsg(&self, msg_hdr: &mut MsgHdrMut, flags: RecvFlags) -> Result<usize> {
|
pub fn recvmsg(
|
||||||
|
&self,
|
||||||
|
bufs: &mut [&mut [u8]],
|
||||||
|
flags: RecvFlags,
|
||||||
|
control: Option<&mut [u8]>,
|
||||||
|
) -> Result<(usize, usize)> {
|
||||||
if !flags.is_empty() {
|
if !flags.is_empty() {
|
||||||
warn!("unsupported flags: {:?}", flags);
|
warn!("unsupported flags: {:?}", flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
let bufs = msg_hdr.get_iovs_mut().as_slices_mut();
|
let data_len = self.readv(bufs)?;
|
||||||
let mut data_len = self.readv(bufs)?;
|
|
||||||
|
|
||||||
// For stream socket, the msg_name is ignored. And other fields are not supported.
|
// For stream socket, the msg_name is ignored. And other fields are not supported.
|
||||||
msg_hdr.set_name_len(0);
|
let control_len = if let Some(msg_control) = control {
|
||||||
|
let control_len = self.read(msg_control)?;
|
||||||
if let Some(msg_control) = msg_hdr.get_control_mut() {
|
|
||||||
data_len += self.read(msg_control)?;
|
|
||||||
|
|
||||||
// For each control message that contains file descriptors (SOL_SOCKET and SCM_RIGHTS),
|
// For each control message that contains file descriptors (SOL_SOCKET and SCM_RIGHTS),
|
||||||
// reassign each fd in the message in receive end.
|
// reassign each fd in the message in receive end.
|
||||||
@ -268,7 +276,6 @@ impl Stream {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.files()
|
.files()
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
|
||||||
.get(send_fd)
|
.get(send_fd)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
current!().add_file(ipc_file.clone(), false)
|
current!().add_file(ipc_file.clone(), false)
|
||||||
@ -276,12 +283,16 @@ impl Stream {
|
|||||||
}
|
}
|
||||||
// Unix credentials need not to be handled here
|
// Unix credentials need not to be handled here
|
||||||
}
|
}
|
||||||
}
|
control_len
|
||||||
Ok(data_len)
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok((data_len, control_len))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// perform shutdown on the socket.
|
/// perform shutdown on the socket.
|
||||||
pub fn shutdown(&self, how: HowToShut) -> Result<()> {
|
pub fn shutdown(&self, how: Shutdown) -> Result<()> {
|
||||||
if let Status::Connected(ref end) = &*self.inner() {
|
if let Status::Connected(ref end) = &*self.inner() {
|
||||||
end.shutdown(how)
|
end.shutdown(how)
|
||||||
} else {
|
} else {
|
||||||
@ -369,13 +380,13 @@ pub enum Status {
|
|||||||
Idle(Info),
|
Idle(Info),
|
||||||
// The listeners are stored in a global data structure indexed by the address.
|
// The listeners are stored in a global data structure indexed by the address.
|
||||||
// The consitency of Status with that data structure should be carefully maintained.
|
// The consitency of Status with that data structure should be carefully maintained.
|
||||||
Listening(Addr),
|
Listening(UnixAddr),
|
||||||
Connected(Endpoint),
|
Connected(Endpoint),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Info {
|
pub struct Info {
|
||||||
addr: Option<Addr>,
|
addr: Option<UnixAddr>,
|
||||||
nonblocking: bool,
|
nonblocking: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -387,11 +398,11 @@ impl Info {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn addr(&self) -> &Option<Addr> {
|
pub fn addr(&self) -> &Option<UnixAddr> {
|
||||||
&self.addr
|
&self.addr
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_addr(&mut self, addr: &Addr) {
|
pub fn set_addr(&mut self, addr: &UnixAddr) {
|
||||||
self.addr = Some(addr.clone());
|
self.addr = Some(addr.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
134
src/libos/src/net/socket/util/addr/c_sock_addr.rs
Normal file
134
src/libos/src/net/socket/util/addr/c_sock_addr.rs
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
use crate::prelude::*;
|
||||||
|
use std::mem::{size_of, size_of_val, MaybeUninit};
|
||||||
|
/// A trait for all C version of C socket addresses.
|
||||||
|
///
|
||||||
|
/// There are four types that implement this trait:
|
||||||
|
/// * `libc::sockaddr_in`
|
||||||
|
/// * `(libc::sockaddr_in, usize)`
|
||||||
|
/// * `(libc::sockaddr_un, usize)`
|
||||||
|
/// * `(libc::sockaddr_storage, usize)`.
|
||||||
|
pub trait CSockAddr {
|
||||||
|
/// The network family of the address.
|
||||||
|
fn c_family(&self) -> libc::sa_family_t;
|
||||||
|
|
||||||
|
/// The address in bytes (excluding the family part).
|
||||||
|
fn c_addr(&self) -> &[u8];
|
||||||
|
|
||||||
|
/// Returns the address in `libc::sockaddr_storage` along with its length.
|
||||||
|
fn to_c_storage(&self) -> (libc::sockaddr_storage, usize) {
|
||||||
|
let mut c_storage =
|
||||||
|
unsafe { MaybeUninit::<libc::sockaddr_storage>::uninit().assume_init() };
|
||||||
|
|
||||||
|
c_storage.ss_family = self.c_family();
|
||||||
|
let offset = size_of_val(&c_storage.ss_family);
|
||||||
|
|
||||||
|
let c_storage_len = offset + self.c_addr().len();
|
||||||
|
assert!(c_storage_len <= size_of::<libc::sockaddr_storage>());
|
||||||
|
|
||||||
|
let c_storage_remain = unsafe {
|
||||||
|
let ptr = (&mut c_storage as *mut _ as *mut u8).add(offset);
|
||||||
|
let len = self.c_addr().len();
|
||||||
|
std::slice::from_raw_parts_mut(ptr, len)
|
||||||
|
};
|
||||||
|
c_storage_remain.copy_from_slice(self.c_addr());
|
||||||
|
(c_storage, c_storage_len)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CSockAddr for libc::sockaddr_in {
|
||||||
|
fn c_family(&self) -> libc::sa_family_t {
|
||||||
|
libc::AF_INET as _
|
||||||
|
}
|
||||||
|
|
||||||
|
fn c_addr(&self) -> &[u8] {
|
||||||
|
// Safety. The slice is part of self.
|
||||||
|
unsafe {
|
||||||
|
let addr_ptr = (self as *const _ as *const u8).add(size_of_val(&self.sin_family));
|
||||||
|
std::slice::from_raw_parts(
|
||||||
|
addr_ptr,
|
||||||
|
size_of::<libc::sockaddr_in>() - size_of_val(&self.sin_family),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CSockAddr for (libc::sockaddr_in, usize) {
|
||||||
|
fn c_family(&self) -> libc::sa_family_t {
|
||||||
|
self.0.c_family()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn c_addr(&self) -> &[u8] {
|
||||||
|
assert!(self.1 == size_of::<libc::sockaddr_in>());
|
||||||
|
self.0.c_addr()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CSockAddr for (libc::sockaddr_in6, usize) {
|
||||||
|
fn c_family(&self) -> libc::sa_family_t {
|
||||||
|
self.0.sin6_family
|
||||||
|
}
|
||||||
|
|
||||||
|
fn c_addr(&self) -> &[u8] {
|
||||||
|
assert!(self.1 == size_of::<libc::sockaddr_in6>());
|
||||||
|
unsafe {
|
||||||
|
let addr_ptr = (&self.0 as *const _ as *const u8).add(size_of_val(&self.c_family()));
|
||||||
|
std::slice::from_raw_parts(
|
||||||
|
addr_ptr,
|
||||||
|
size_of::<libc::sockaddr_in6>() - size_of_val(&self.c_family()),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CSockAddr for (libc::sockaddr_un, usize) {
|
||||||
|
fn c_family(&self) -> libc::sa_family_t {
|
||||||
|
libc::AF_UNIX as _
|
||||||
|
}
|
||||||
|
|
||||||
|
fn c_addr(&self) -> &[u8] {
|
||||||
|
assert!(
|
||||||
|
size_of::<libc::sa_family_t>() <= self.1 && self.1 <= size_of::<libc::sockaddr_un>()
|
||||||
|
);
|
||||||
|
// Safety. The slice is part of self.
|
||||||
|
unsafe {
|
||||||
|
let addr_ptr = (&self.0 as *const _ as *const u8).add(size_of_val(&self.0.sun_family));
|
||||||
|
std::slice::from_raw_parts(addr_ptr, self.1 - size_of_val(&self.0.sun_family))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CSockAddr for (libc::sockaddr_nl, usize) {
|
||||||
|
fn c_family(&self) -> libc::sa_family_t {
|
||||||
|
libc::AF_NETLINK as _
|
||||||
|
}
|
||||||
|
|
||||||
|
fn c_addr(&self) -> &[u8] {
|
||||||
|
assert!(self.1 == size_of::<libc::sockaddr_nl>());
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let addr_ptr = (&self.0 as *const _ as *const u8).add(size_of_val(&self.c_family()));
|
||||||
|
std::slice::from_raw_parts(
|
||||||
|
addr_ptr,
|
||||||
|
size_of::<libc::sockaddr_nl>() - size_of_val(&self.c_family()),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CSockAddr for (libc::sockaddr_storage, usize) {
|
||||||
|
fn c_family(&self) -> libc::sa_family_t {
|
||||||
|
self.0.ss_family
|
||||||
|
}
|
||||||
|
|
||||||
|
fn c_addr(&self) -> &[u8] {
|
||||||
|
assert!(
|
||||||
|
size_of::<libc::sa_family_t>() <= self.1
|
||||||
|
&& self.1 <= size_of::<libc::sockaddr_storage>()
|
||||||
|
);
|
||||||
|
// Safety. The slice is part of self.
|
||||||
|
unsafe {
|
||||||
|
let addr_ptr = (&self.0 as *const _ as *const u8).add(size_of_val(&self.0.ss_family));
|
||||||
|
std::slice::from_raw_parts(addr_ptr, self.1 - size_of_val(&self.0.ss_family))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
137
src/libos/src/net/socket/util/addr/ipv4.rs
Normal file
137
src/libos/src/net/socket/util/addr/ipv4.rs
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
use std::any::Any;
|
||||||
|
use std::fmt::{self, Debug};
|
||||||
|
|
||||||
|
use super::{Addr, CSockAddr, Domain, RawAddr};
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
/// An IPv4 socket address, consisting of an IPv4 address and a port.
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub struct Ipv4SocketAddr {
|
||||||
|
ip: Ipv4Addr,
|
||||||
|
port: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Addr for Ipv4SocketAddr {
|
||||||
|
fn domain() -> Domain {
|
||||||
|
Domain::INET
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_c_storage(c_addr: &libc::sockaddr_storage, c_addr_len: usize) -> Result<Self> {
|
||||||
|
if c_addr_len > std::mem::size_of::<libc::sockaddr_storage>() {
|
||||||
|
return_errno!(EINVAL, "address length is too large");
|
||||||
|
}
|
||||||
|
|
||||||
|
// The c_addr_len is certainly not smaller than the length of IN_ADDR_ANY.
|
||||||
|
// https://en.wikipedia.org/wiki/IPv4
|
||||||
|
if c_addr_len < std::mem::size_of::<libc::sockaddr_in>() {
|
||||||
|
return_errno!(EINVAL, "address length is too small");
|
||||||
|
}
|
||||||
|
// Safe to convert from sockaddr_storage to sockaddr_in
|
||||||
|
let c_addr = unsafe { std::mem::transmute(c_addr) };
|
||||||
|
Self::from_c(c_addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_c_storage(&self) -> (libc::sockaddr_storage, usize) {
|
||||||
|
let c_in_addr = self.to_c();
|
||||||
|
c_in_addr.to_c_storage()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_default(&self) -> bool {
|
||||||
|
let inaddr_any = Self::default();
|
||||||
|
*self == inaddr_any
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ipv4SocketAddr {
|
||||||
|
pub fn new(ip: Ipv4Addr, port: u16) -> Self {
|
||||||
|
Self { ip, port }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_c(c_addr: &libc::sockaddr_in) -> Result<Self> {
|
||||||
|
if c_addr.sin_family != libc::AF_INET as libc::sa_family_t {
|
||||||
|
return_errno!(EINVAL, "an ipv4 address is expected");
|
||||||
|
}
|
||||||
|
Ok(Self {
|
||||||
|
port: u16::from_be(c_addr.sin_port),
|
||||||
|
ip: Ipv4Addr::from_c(&c_addr.sin_addr),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_c(&self) -> libc::sockaddr_in {
|
||||||
|
libc::sockaddr_in {
|
||||||
|
sin_family: libc::AF_INET as _,
|
||||||
|
sin_port: self.port.to_be(),
|
||||||
|
sin_addr: self.ip.to_c(),
|
||||||
|
sin_zero: [0; 8],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_raw(&self) -> RawAddr {
|
||||||
|
let (storage, len) = self.to_c_storage();
|
||||||
|
RawAddr::from_c_storage(&storage, len)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ip(&self) -> &Ipv4Addr {
|
||||||
|
&self.ip
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn port(&self) -> u16 {
|
||||||
|
self.port
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_ip(&mut self, new_ip: Ipv4Addr) {
|
||||||
|
self.ip = new_ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_port(&mut self, new_port: u16) {
|
||||||
|
self.port = new_port;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Ipv4SocketAddr {
|
||||||
|
fn default() -> Self {
|
||||||
|
let addr = Ipv4Addr::new(0, 0, 0, 0);
|
||||||
|
Self::new(addr, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An Ipv4 address.
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||||
|
pub struct Ipv4Addr([u8; 4] /* big endian */);
|
||||||
|
|
||||||
|
impl Ipv4Addr {
|
||||||
|
/// Creates a new IPv4 address of `a.b.c.d`.
|
||||||
|
pub fn new(a: u8, b: u8, c: u8, d: u8) -> Self {
|
||||||
|
Self([a, b, c, d])
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new IPv4 address from its C counterpart.
|
||||||
|
pub fn from_c(c_addr: &libc::in_addr) -> Self {
|
||||||
|
Self(c_addr.s_addr.to_ne_bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the C counterpart.
|
||||||
|
pub fn to_c(&self) -> libc::in_addr {
|
||||||
|
libc::in_addr {
|
||||||
|
s_addr: u32::from_ne_bytes(self.0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the four digits that make up the address.
|
||||||
|
///
|
||||||
|
/// Assuming the address is `a.b.c.d`, the returned value would be `[a, b, c, d]`.
|
||||||
|
pub fn octets(&self) -> &[u8; 4] {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for Ipv4Addr {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
let [a, b, c, d] = *self.octets();
|
||||||
|
write!(f, "Ipv4Addr ({}.{}.{}.{})", &a, &b, &c, &d)
|
||||||
|
}
|
||||||
|
}
|
115
src/libos/src/net/socket/util/addr/ipv6.rs
Normal file
115
src/libos/src/net/socket/util/addr/ipv6.rs
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
use std::any::Any;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
use super::RawAddr;
|
||||||
|
use super::{Addr, CSockAddr, Domain};
|
||||||
|
use crate::prelude::*;
|
||||||
|
use libc::in6_addr;
|
||||||
|
use libc::sockaddr_in6;
|
||||||
|
|
||||||
|
pub use std::net::Ipv6Addr;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub struct Ipv6SocketAddr {
|
||||||
|
ip: Ipv6Addr,
|
||||||
|
port: u16,
|
||||||
|
flowinfo: u32,
|
||||||
|
scope_id: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Addr for Ipv6SocketAddr {
|
||||||
|
fn domain() -> Domain {
|
||||||
|
Domain::INET6
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_c_storage(c_addr: &libc::sockaddr_storage, c_addr_len: usize) -> Result<Self> {
|
||||||
|
if c_addr_len > std::mem::size_of::<libc::sockaddr_storage>() {
|
||||||
|
return_errno!(EINVAL, "address length is too large");
|
||||||
|
}
|
||||||
|
|
||||||
|
if c_addr_len < std::mem::size_of::<sockaddr_in6>() {
|
||||||
|
return_errno!(EINVAL, "address length is too small");
|
||||||
|
}
|
||||||
|
// Safe to convert from sockaddr_storage to sockaddr_in
|
||||||
|
let c_addr: &sockaddr_in6 = unsafe { std::mem::transmute(c_addr) };
|
||||||
|
Self::from_c(c_addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_c_storage(&self) -> (libc::sockaddr_storage, usize) {
|
||||||
|
let c_addr = self.to_c();
|
||||||
|
(c_addr, std::mem::size_of::<libc::sockaddr_in6>()).to_c_storage()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_default(&self) -> bool {
|
||||||
|
let in6addr_any_init = Self::default();
|
||||||
|
*self == in6addr_any_init
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ipv6SocketAddr {
|
||||||
|
pub fn new(ip: Ipv6Addr, port: u16, flowinfo: u32, scope_id: u32) -> Self {
|
||||||
|
Self {
|
||||||
|
ip,
|
||||||
|
port,
|
||||||
|
flowinfo,
|
||||||
|
scope_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_c(c_addr: &libc::sockaddr_in6) -> Result<Self> {
|
||||||
|
if c_addr.sin6_family != libc::AF_INET6 as libc::sa_family_t {
|
||||||
|
return_errno!(EINVAL, "an ipv6 address is expected");
|
||||||
|
}
|
||||||
|
Ok(Self {
|
||||||
|
port: u16::from_be(c_addr.sin6_port),
|
||||||
|
ip: Ipv6Addr::from(c_addr.sin6_addr.s6_addr),
|
||||||
|
flowinfo: u32::from_be(c_addr.sin6_flowinfo),
|
||||||
|
scope_id: u32::from_be(c_addr.sin6_scope_id),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_c(&self) -> libc::sockaddr_in6 {
|
||||||
|
let in6_addr = in6_addr {
|
||||||
|
s6_addr: self.ip.octets(),
|
||||||
|
};
|
||||||
|
libc::sockaddr_in6 {
|
||||||
|
sin6_family: libc::AF_INET6 as _,
|
||||||
|
sin6_port: self.port.to_be(),
|
||||||
|
sin6_addr: in6_addr,
|
||||||
|
sin6_flowinfo: self.flowinfo.to_be(),
|
||||||
|
sin6_scope_id: self.flowinfo.to_be(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_raw(&self) -> RawAddr {
|
||||||
|
let (storage, len) = self.to_c_storage();
|
||||||
|
RawAddr::from_c_storage(&storage, len)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ip(&self) -> &Ipv6Addr {
|
||||||
|
&self.ip
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn port(&self) -> u16 {
|
||||||
|
self.port
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_ip(&mut self, new_ip: Ipv6Addr) {
|
||||||
|
self.ip = new_ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_port(&mut self, new_port: u16) {
|
||||||
|
self.port = new_port;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Ipv6SocketAddr {
|
||||||
|
fn default() -> Self {
|
||||||
|
let addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0);
|
||||||
|
Self::new(addr, 0, 0, 0)
|
||||||
|
}
|
||||||
|
}
|
87
src/libos/src/net/socket/util/addr/mod.rs
Normal file
87
src/libos/src/net/socket/util/addr/mod.rs
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
use std::any::Any;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
use crate::net::Domain;
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
mod c_sock_addr;
|
||||||
|
mod ipv4;
|
||||||
|
mod ipv6;
|
||||||
|
mod raw_addr;
|
||||||
|
mod unix_addr;
|
||||||
|
|
||||||
|
/// A trait for network addresses.
|
||||||
|
pub trait Addr: Clone + Debug + Default + PartialEq + Send + Sync {
|
||||||
|
/// Return the domain that the address belongs to.
|
||||||
|
fn domain() -> Domain
|
||||||
|
where
|
||||||
|
Self: Sized;
|
||||||
|
|
||||||
|
/// Construct a new address from C's sockaddr_storage.
|
||||||
|
///
|
||||||
|
/// The length argument specify how much bytes in the given sockaddr_storage are to be
|
||||||
|
/// interpreted as parts of the address.
|
||||||
|
fn from_c_storage(c_addr: &libc::sockaddr_storage, c_addr_len: usize) -> Result<Self>
|
||||||
|
where
|
||||||
|
Self: Sized;
|
||||||
|
|
||||||
|
/// Converts the address to C's sockaddr_storage.
|
||||||
|
///
|
||||||
|
/// The actual length used in sockaddr_storage is also returned.
|
||||||
|
fn to_c_storage(&self) -> (libc::sockaddr_storage, usize);
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn Any;
|
||||||
|
|
||||||
|
fn is_default(&self) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub use self::c_sock_addr::CSockAddr;
|
||||||
|
pub use self::ipv4::{Ipv4Addr, Ipv4SocketAddr};
|
||||||
|
pub use self::ipv6::{Ipv6Addr, Ipv6SocketAddr};
|
||||||
|
pub use self::raw_addr::RawAddr;
|
||||||
|
pub use self::unix_addr::UnixAddr;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::mem::size_of;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ipv4_to_and_from_c() {
|
||||||
|
let addr = [127u8, 0, 0, 1];
|
||||||
|
let port = 8888u16;
|
||||||
|
|
||||||
|
let c_addr = libc::sockaddr_in {
|
||||||
|
sin_family: libc::AF_INET as _,
|
||||||
|
sin_port: port.to_be(),
|
||||||
|
sin_addr: libc::in_addr {
|
||||||
|
s_addr: u32::from_be_bytes(addr).to_be(),
|
||||||
|
},
|
||||||
|
sin_zero: [0u8; 8],
|
||||||
|
};
|
||||||
|
|
||||||
|
let addr = {
|
||||||
|
let addr = Ipv4Addr::new(addr[0], addr[1], addr[2], addr[3]);
|
||||||
|
Ipv4SocketAddr::new(addr, port)
|
||||||
|
};
|
||||||
|
|
||||||
|
check_to_and_from_c(&c_addr, &addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_to_and_from_c<T: CSockAddr, U: Addr>(c_addr: &T, addr: &U) {
|
||||||
|
let c_addr_storage = c_addr.to_c_storage();
|
||||||
|
|
||||||
|
// To C
|
||||||
|
assert!(are_sock_addrs_equal(c_addr, &addr.to_c_storage()));
|
||||||
|
assert!(are_sock_addrs_equal(&c_addr_storage, &addr.to_c_storage()));
|
||||||
|
|
||||||
|
// From C
|
||||||
|
let (c_addr_storage, c_addr_len) = c_addr_storage;
|
||||||
|
assert!(&U::from_c_storage(&c_addr_storage, c_addr_len).unwrap() == addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn are_sock_addrs_equal<T: CSockAddr, U: CSockAddr>(one: &T, other: &U) -> bool {
|
||||||
|
one.c_family() == other.c_family() && one.c_addr() == other.c_addr()
|
||||||
|
}
|
||||||
|
}
|
@ -2,25 +2,33 @@ use super::*;
|
|||||||
use std::*;
|
use std::*;
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct SockAddr {
|
pub struct RawAddr {
|
||||||
storage: libc::sockaddr_storage,
|
storage: libc::sockaddr_storage,
|
||||||
len: usize,
|
len: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: add more fields
|
// TODO: add more fields
|
||||||
impl fmt::Debug for SockAddr {
|
impl fmt::Debug for RawAddr {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
f.debug_struct("SockAddr")
|
f.debug_struct("RawAddr")
|
||||||
.field(
|
.field("family", &Domain::try_from(self.storage.ss_family).unwrap())
|
||||||
"family",
|
|
||||||
&AddressFamily::try_from(self.storage.ss_family).unwrap(),
|
|
||||||
)
|
|
||||||
.field("len", &self.len)
|
.field("len", &self.len)
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SockAddr {
|
impl RawAddr {
|
||||||
|
pub fn from_c_storage(c_addr: &libc::sockaddr_storage, c_addr_len: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
storage: *c_addr,
|
||||||
|
len: c_addr_len,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_c_storage(&self) -> (libc::sockaddr_storage, usize) {
|
||||||
|
(self.storage, self.len)
|
||||||
|
}
|
||||||
|
|
||||||
// Caller should guarentee the sockaddr and addr_len are valid
|
// Caller should guarentee the sockaddr and addr_len are valid
|
||||||
pub unsafe fn try_from_raw(
|
pub unsafe fn try_from_raw(
|
||||||
sockaddr: *const libc::sockaddr,
|
sockaddr: *const libc::sockaddr,
|
||||||
@ -34,13 +42,13 @@ impl SockAddr {
|
|||||||
return_errno!(EINVAL, "the address is too long.");
|
return_errno!(EINVAL, "the address is too long.");
|
||||||
}
|
}
|
||||||
|
|
||||||
match AddressFamily::try_from((*sockaddr).sa_family)? {
|
match Domain::try_from((*sockaddr).sa_family)? {
|
||||||
AddressFamily::INET => {
|
Domain::INET => {
|
||||||
if addr_len < std::mem::size_of::<libc::sockaddr_in>() as u32 {
|
if addr_len < std::mem::size_of::<libc::sockaddr_in>() as u32 {
|
||||||
return_errno!(EINVAL, "short ipv4 address.");
|
return_errno!(EINVAL, "short ipv4 address.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AddressFamily::INET6 => {
|
Domain::INET6 => {
|
||||||
let ipv6_addr_len = std::mem::size_of::<libc::sockaddr_in6>() as u32;
|
let ipv6_addr_len = std::mem::size_of::<libc::sockaddr_in6>() as u32;
|
||||||
// Omit sin6_scope_id when it is not fully provided
|
// Omit sin6_scope_id when it is not fully provided
|
||||||
// 4 represents the size of sin6_scope_id which is not a must
|
// 4 represents the size of sin6_scope_id which is not a must
|
||||||
@ -110,7 +118,7 @@ impl SockAddr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for SockAddr {
|
impl Default for RawAddr {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() };
|
let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() };
|
||||||
Self {
|
Self {
|
212
src/libos/src/net/socket/util/addr/unix_addr.rs
Normal file
212
src/libos/src/net/socket/util/addr/unix_addr.rs
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
use crate::net::socket::CSockAddr;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
use sgx_trts::c_str::CStr;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::{cmp, mem, slice, str};
|
||||||
|
|
||||||
|
const MAX_PATH_LEN: usize = 108;
|
||||||
|
const SUN_FAMILY_LEN: usize = mem::size_of::<libc::sa_family_t>();
|
||||||
|
lazy_static! {
|
||||||
|
static ref SUN_PATH_OFFSET: usize = memoffset::offset_of!(libc::sockaddr_un, sun_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
|
pub enum UnixAddr {
|
||||||
|
Unnamed,
|
||||||
|
File(Option<usize>, UnixPath), // An optional inode number and path. Use inode if there is one.
|
||||||
|
Abstract(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UnixAddr {
|
||||||
|
/// Construct a unix address from its C counterpart.
|
||||||
|
///
|
||||||
|
/// The argument `c_len` specifies the length of the valid part in the given
|
||||||
|
/// C address.
|
||||||
|
pub fn from_c(c_addr: &libc::sockaddr_un, c_len: usize) -> Result<Self> {
|
||||||
|
// Sanity checks
|
||||||
|
if c_addr.sun_family != libc::AF_UNIX as libc::sa_family_t {
|
||||||
|
return_errno!(EINVAL, "an unix address is expected");
|
||||||
|
}
|
||||||
|
if c_len < std::mem::size_of::<libc::sa_family_t>() {
|
||||||
|
return_errno!(EINVAL, "the length of the address is too small");
|
||||||
|
} else if c_len > std::mem::size_of::<libc::sockaddr_un>() {
|
||||||
|
return_errno!(EINVAL, "the length of the address is too large");
|
||||||
|
}
|
||||||
|
|
||||||
|
if c_len == std::mem::size_of::<libc::sa_family_t>() {
|
||||||
|
return Ok(Self::Unnamed);
|
||||||
|
}
|
||||||
|
|
||||||
|
let path_len = c_len - std::mem::size_of::<libc::sa_family_t>();
|
||||||
|
debug_assert!(path_len > 1);
|
||||||
|
if path_len == 1 {
|
||||||
|
// Both pathname and abstract addresses require a path_len greater than 1.
|
||||||
|
return_errno!(EINVAL, "the pathname must not be empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
// A pathname address
|
||||||
|
if c_addr.sun_path[0] != 0 {
|
||||||
|
// More sanity check
|
||||||
|
let last_char = c_addr.sun_path[path_len - 1];
|
||||||
|
if last_char != 0 {
|
||||||
|
return_errno!(EINVAL, "the pathname is not null-terminated");
|
||||||
|
}
|
||||||
|
|
||||||
|
let pathname = {
|
||||||
|
// Safety. Converting from &[c_char] to &[i8] is harmless.
|
||||||
|
let path_slice: &[i8] = unsafe {
|
||||||
|
let char_slice = &c_addr.sun_path[..(path_len - 1)];
|
||||||
|
std::mem::transmute(char_slice)
|
||||||
|
};
|
||||||
|
let path_cstr = unsafe { CStr::from_ptr(path_slice.as_ptr()) };
|
||||||
|
if path_cstr.to_bytes_with_nul().len() > MAX_PATH_LEN {
|
||||||
|
return_errno!(EINVAL, "no null in the address");
|
||||||
|
}
|
||||||
|
path_cstr
|
||||||
|
.to_str()
|
||||||
|
.map_err(|_| errno!(EINVAL, "path is not UTF8"))?
|
||||||
|
.to_string()
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Self::File(None, UnixPath::new(&pathname)))
|
||||||
|
}
|
||||||
|
// An abstract address
|
||||||
|
else {
|
||||||
|
// Safety. Converting from &[c_char] to &[u8] is harmless.
|
||||||
|
let u8_slice: &[u8] = unsafe {
|
||||||
|
let char_slice = &c_addr.sun_path[1..(path_len)];
|
||||||
|
std::mem::transmute(char_slice)
|
||||||
|
};
|
||||||
|
Ok(Self::Abstract(
|
||||||
|
str::from_utf8(u8_slice).unwrap().to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_c_storage(c_addr: &libc::sockaddr_storage, c_addr_len: usize) -> Result<Self> {
|
||||||
|
if (c_addr_len) > std::mem::size_of::<libc::sockaddr_storage>() {
|
||||||
|
return_errno!(EINVAL, "address length is too large");
|
||||||
|
}
|
||||||
|
// Safety. Convert from sockaddr_storage to sockaddr_un is harmless.
|
||||||
|
let c_addr = unsafe { std::mem::transmute(c_addr) };
|
||||||
|
unsafe { Self::from_c(c_addr, c_addr_len) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn copy_to_slice(&self, dst: &mut [u8]) -> usize {
|
||||||
|
let (raw_addr, addr_len) = self.to_c();
|
||||||
|
let src =
|
||||||
|
unsafe { std::slice::from_raw_parts(&raw_addr as *const _ as *const u8, addr_len) };
|
||||||
|
let copied = std::cmp::min(dst.len(), addr_len);
|
||||||
|
dst[..copied].copy_from_slice(&src[..copied]);
|
||||||
|
copied
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn raw_len(&self) -> usize {
|
||||||
|
/// The '/0' at the end of Self::File counts
|
||||||
|
match self.path_str() {
|
||||||
|
Ok(str) => str.len() + 1 + *SUN_PATH_OFFSET,
|
||||||
|
Err(_) => 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn path_str(&self) -> Result<&str> {
|
||||||
|
match self {
|
||||||
|
Self::File(_, unix_path) => Ok(&unix_path.path_str()),
|
||||||
|
Self::Abstract(path) => Ok(&path),
|
||||||
|
Self::Unnamed => return_errno!(EINVAL, "can't get path name for unnamed socket"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_c_storage(&self) -> (libc::sockaddr_storage, usize) {
|
||||||
|
let c_un_addr = self.to_c();
|
||||||
|
c_un_addr.to_c_storage()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_raw(&self) -> RawAddr {
|
||||||
|
let (storage, addr_len) = self.to_c_storage();
|
||||||
|
RawAddr::from_c_storage(&storage, addr_len)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_c(&self) -> (libc::sockaddr_un, usize) {
|
||||||
|
const FAMILY_LEN: usize = std::mem::size_of::<libc::sa_family_t>();
|
||||||
|
|
||||||
|
let mut addr: libc::sockaddr_un = unsafe { mem::zeroed() };
|
||||||
|
addr.sun_family = Domain::LOCAL as libc::sa_family_t;
|
||||||
|
|
||||||
|
let addr_len = match self {
|
||||||
|
Self::Unnamed => FAMILY_LEN,
|
||||||
|
Self::File(_, unix_path) => {
|
||||||
|
let path_str = unix_path.path_str();
|
||||||
|
let buf_len = path_str.len();
|
||||||
|
/// addr is initialized to all zeros and try_from_raw guarentees
|
||||||
|
/// unix_path length is shorter than sun_path, so sun_path here
|
||||||
|
/// will always have a null terminator
|
||||||
|
addr.sun_path[..buf_len]
|
||||||
|
.copy_from_slice(unsafe { &*(path_str.as_bytes() as *const _ as *const [i8]) });
|
||||||
|
buf_len + *SUN_PATH_OFFSET + 1
|
||||||
|
}
|
||||||
|
Self::Abstract(path_str) => {
|
||||||
|
addr.sun_path[0] = 0;
|
||||||
|
let buf_len = path_str.len() + 1;
|
||||||
|
addr.sun_path[1..buf_len]
|
||||||
|
.copy_from_slice(unsafe { &*(path_str.as_bytes() as *const _ as *const [i8]) });
|
||||||
|
buf_len + *SUN_PATH_OFFSET
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
(addr, addr_len)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for UnixAddr {
|
||||||
|
fn default() -> Self {
|
||||||
|
UnixAddr::Unnamed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
|
pub struct UnixPath {
|
||||||
|
inner: PathBuf,
|
||||||
|
/// Holds the cwd when a relative path is created
|
||||||
|
cwd: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UnixPath {
|
||||||
|
pub fn new(path: &str) -> Self {
|
||||||
|
let inner = PathBuf::from(path);
|
||||||
|
let is_absolute = inner.is_absolute();
|
||||||
|
Self {
|
||||||
|
inner: inner,
|
||||||
|
cwd: if is_absolute {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
let thread = current!();
|
||||||
|
let fs = thread.fs().read().unwrap();
|
||||||
|
let cwd = fs.cwd().to_owned();
|
||||||
|
|
||||||
|
Some(cwd)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn absolute(&self) -> String {
|
||||||
|
let path_str = self.path_str();
|
||||||
|
if self.inner.is_absolute() {
|
||||||
|
path_str.to_string()
|
||||||
|
} else {
|
||||||
|
let mut prefix = self.cwd.as_ref().unwrap().clone();
|
||||||
|
if prefix.ends_with("/") {
|
||||||
|
prefix.push_str(path_str);
|
||||||
|
} else {
|
||||||
|
prefix.push_str("/");
|
||||||
|
prefix.push_str(path_str);
|
||||||
|
}
|
||||||
|
prefix
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn path_str(&self) -> &str {
|
||||||
|
self.inner.to_str().unwrap()
|
||||||
|
}
|
||||||
|
}
|
113
src/libos/src/net/socket/util/any_addr.rs
Normal file
113
src/libos/src/net/socket/util/any_addr.rs
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
use std::mem::{self, MaybeUninit};
|
||||||
|
|
||||||
|
use crate::net::socket::Domain;
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
use super::{Addr, CSockAddr, Ipv4Addr, Ipv4SocketAddr, Ipv6SocketAddr, RawAddr, UnixAddr};
|
||||||
|
use num_enum::IntoPrimitive;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum AnyAddr {
|
||||||
|
Ipv4(Ipv4SocketAddr),
|
||||||
|
Ipv6(Ipv6SocketAddr),
|
||||||
|
Unix(UnixAddr),
|
||||||
|
Raw(RawAddr),
|
||||||
|
Unspec,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AnyAddr {
|
||||||
|
pub fn from_c_storage(c_addr: &libc::sockaddr_storage, c_addr_len: usize) -> Result<Self> {
|
||||||
|
let any_addr = match c_addr.ss_family as _ {
|
||||||
|
libc::AF_INET => {
|
||||||
|
let ipv4_addr = Ipv4SocketAddr::from_c_storage(c_addr, c_addr_len)?;
|
||||||
|
Self::Ipv4(ipv4_addr)
|
||||||
|
}
|
||||||
|
libc::AF_INET6 => {
|
||||||
|
let ipv6_addr = Ipv6SocketAddr::from_c_storage(c_addr, c_addr_len)?;
|
||||||
|
Self::Ipv6(ipv6_addr)
|
||||||
|
}
|
||||||
|
libc::AF_UNSPEC => Self::Unspec,
|
||||||
|
libc::AF_UNIX | libc::AF_LOCAL => {
|
||||||
|
let unix_addr = UnixAddr::from_c_storage(c_addr, c_addr_len)?;
|
||||||
|
Self::Unix(unix_addr)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let raw_addr = RawAddr::from_c_storage(c_addr, c_addr_len);
|
||||||
|
Self::Raw(raw_addr)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok(any_addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_c_storage(&self) -> (libc::sockaddr_storage, usize) {
|
||||||
|
match self {
|
||||||
|
Self::Ipv4(ipv4_addr) => ipv4_addr.to_c_storage(),
|
||||||
|
Self::Ipv6(ipv6_addr) => ipv6_addr.to_c_storage(),
|
||||||
|
Self::Unix(unix_addr) => unix_addr.to_c_storage(),
|
||||||
|
Self::Raw(raw_addr) => raw_addr.to_c_storage(),
|
||||||
|
Self::Unspec => {
|
||||||
|
let mut sockaddr_storage =
|
||||||
|
unsafe { MaybeUninit::<libc::sockaddr_storage>::uninit().assume_init() };
|
||||||
|
sockaddr_storage.ss_family = libc::AF_UNSPEC as _;
|
||||||
|
(sockaddr_storage, mem::size_of::<libc::sa_family_t>())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_raw(&self) -> RawAddr {
|
||||||
|
match self {
|
||||||
|
Self::Ipv4(ipv4_addr) => ipv4_addr.to_raw(),
|
||||||
|
Self::Ipv6(ipv6_addr) => ipv6_addr.to_raw(),
|
||||||
|
Self::Unix(unix_addr) => unix_addr.to_raw(),
|
||||||
|
Self::Raw(raw_addr) => *raw_addr,
|
||||||
|
Self::Unspec => {
|
||||||
|
let mut sockaddr_storage =
|
||||||
|
unsafe { MaybeUninit::<libc::sockaddr_storage>::uninit().assume_init() };
|
||||||
|
sockaddr_storage.ss_family = libc::AF_UNSPEC as _;
|
||||||
|
RawAddr::from_c_storage(&sockaddr_storage, mem::size_of::<libc::sa_family_t>())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_unix(&self) -> Result<&UnixAddr> {
|
||||||
|
match self {
|
||||||
|
Self::Unix(unix_addr) => Ok(unix_addr),
|
||||||
|
_ => return_errno!(EAFNOSUPPORT, "not unix address"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_ipv4(&self) -> Option<&Ipv4SocketAddr> {
|
||||||
|
match self {
|
||||||
|
Self::Ipv4(ipv4_addr) => Some(ipv4_addr),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_ipv4(&self) -> Result<&Ipv4SocketAddr> {
|
||||||
|
match self {
|
||||||
|
Self::Ipv4(ipv4_addr) => Ok(ipv4_addr),
|
||||||
|
_ => return_errno!(EAFNOSUPPORT, "not ipv4 address"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_ipv6(&self) -> Result<&Ipv6SocketAddr> {
|
||||||
|
match self {
|
||||||
|
Self::Ipv6(ipv6_addr) => Ok(ipv6_addr),
|
||||||
|
_ => return_errno!(EAFNOSUPPORT, "not ipv6 address"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_unspec(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Self::Unspec => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_slice(&self) -> &[u8] {
|
||||||
|
let (storage, len) = self.to_c_storage();
|
||||||
|
let addr = &storage as *const _ as *const _;
|
||||||
|
unsafe { std::slice::from_raw_parts(addr as *const u8, len) }
|
||||||
|
}
|
||||||
|
}
|
@ -1,10 +1,11 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
use num_enum::{IntoPrimitive, TryFromPrimitive};
|
||||||
|
|
||||||
// The protocol family generally is the same as the address family
|
// The protocol family generally is the same as the address family
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, IntoPrimitive, TryFromPrimitive)]
|
||||||
#[repr(u16)]
|
#[repr(u16)]
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
pub enum AddressFamily {
|
pub enum Domain {
|
||||||
UNSPEC = 0,
|
UNSPEC = 0,
|
||||||
LOCAL = 1,
|
LOCAL = 1,
|
||||||
/* Hide the families with the same number
|
/* Hide the families with the same number
|
||||||
@ -60,7 +61,7 @@ pub enum AddressFamily {
|
|||||||
MAX = 45,
|
MAX = 45,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AddressFamily {
|
impl Domain {
|
||||||
pub fn try_from(af: u16) -> Result<Self> {
|
pub fn try_from(af: u16) -> Result<Self> {
|
||||||
if af >= Self::MAX as u16 {
|
if af >= Self::MAX as u16 {
|
||||||
return_errno!(EINVAL, "Unknown address family");
|
return_errno!(EINVAL, "Unknown address family");
|
39
src/libos/src/net/socket/util/flags.rs
Normal file
39
src/libos/src/net/socket/util/flags.rs
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
use bitflags::bitflags;
|
||||||
|
|
||||||
|
// Flags to use when sending data through a socket
|
||||||
|
bitflags! {
|
||||||
|
pub struct SendFlags: i32 {
|
||||||
|
const MSG_OOB = 0x01; // Sends out-of-band data on sockets
|
||||||
|
const MSG_DONTROUTE = 0x04; // Don't use a gateway to send out the packet
|
||||||
|
const MSG_DONTWAIT = 0x40; // Nonblocking io
|
||||||
|
const MSG_EOR = 0x80; // End of record
|
||||||
|
const MSG_CONFIRM = 0x0800; // Confirm path validity
|
||||||
|
const MSG_NOSIGNAL = 0x4000; // Do not generate SIGPIPE
|
||||||
|
const MSG_MORE = 0x8000; // Sender will send more
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flags to use when receiving data through a socket
|
||||||
|
bitflags! {
|
||||||
|
pub struct RecvFlags: i32 {
|
||||||
|
const MSG_OOB = 0x01; // Recv out-of-band data
|
||||||
|
const MSG_PEEK = 0x02; // Return data without removing that
|
||||||
|
const MSG_TRUNC = 0x20; // Return the real length of the packet or datagram
|
||||||
|
const MSG_DONTWAIT = 0x40; // Nonblocking io
|
||||||
|
const MSG_WAITALL = 0x0100; // Wait for a full request
|
||||||
|
const MSG_ERRQUEUE = 0x2000; // Fetch message from error queue
|
||||||
|
// recvmsg only
|
||||||
|
const MSG_CMSG_CLOEXEC = 0x40000000; // Set close_on_exec for file descriptor received through SCM_RIGHTS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
pub struct MsgFlags: i32 {
|
||||||
|
const MSG_OOB = 0x01; // Expedited or out-of-band data was received
|
||||||
|
const MSG_CTRUNC = 0x08; // Some control data was discarded
|
||||||
|
const MSG_TRUNC = 0x20; // The trailing portion of a datagram was discarded
|
||||||
|
const MSG_EOR = 0x80; // End of record
|
||||||
|
const MSG_ERRQUEUE = 0x2000; // Fetch message from error queue
|
||||||
|
const MSG_NOTIFICATION = 0x8000; // Only applicable to SCTP socket
|
||||||
|
}
|
||||||
|
}
|
27
src/libos/src/net/socket/util/mod.rs
Normal file
27
src/libos/src/net/socket/util/mod.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
use crate::prelude::*;
|
||||||
|
use crate::untrusted::{
|
||||||
|
SliceAsMutPtrAndLen, SliceAsPtrAndLen, UntrustedSlice, UntrustedSliceAlloc,
|
||||||
|
};
|
||||||
|
use std;
|
||||||
|
|
||||||
|
mod addr;
|
||||||
|
mod any_addr;
|
||||||
|
mod domain;
|
||||||
|
mod flags;
|
||||||
|
mod iovs;
|
||||||
|
mod msg;
|
||||||
|
mod protocol;
|
||||||
|
mod shutdown;
|
||||||
|
mod r#type;
|
||||||
|
|
||||||
|
pub use self::addr::{
|
||||||
|
Addr, CSockAddr, Ipv4Addr, Ipv4SocketAddr, Ipv6SocketAddr, RawAddr, UnixAddr,
|
||||||
|
};
|
||||||
|
pub use self::any_addr::AnyAddr;
|
||||||
|
pub use self::domain::Domain;
|
||||||
|
pub use self::flags::{MsgFlags, RecvFlags, SendFlags};
|
||||||
|
pub use self::iovs::{Iovs, IovsMut, SliceAsLibcIovec};
|
||||||
|
pub use self::msg::{CMessages, CmsgData};
|
||||||
|
pub use self::protocol::SocketProtocol;
|
||||||
|
pub use self::r#type::Type;
|
||||||
|
pub use self::shutdown::Shutdown;
|
115
src/libos/src/net/socket/util/msg.rs
Normal file
115
src/libos/src/net/socket/util/msg.rs
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
/// Socket message and its flags.
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
/// This struct is used to iterate through the control messages.
|
||||||
|
///
|
||||||
|
/// `cmsghdr` is a C struct for ancillary data object information of a unix socket.
|
||||||
|
pub struct CMessages<'a> {
|
||||||
|
buffer: &'a [u8],
|
||||||
|
current: Option<&'a libc::cmsghdr>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for CMessages<'a> {
|
||||||
|
type Item = CmsgData<'a>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
let cmsg = unsafe {
|
||||||
|
let mut msg: libc::msghdr = core::mem::zeroed();
|
||||||
|
msg.msg_control = self.buffer.as_ptr() as *mut _;
|
||||||
|
msg.msg_controllen = self.buffer.len() as _;
|
||||||
|
|
||||||
|
let cmsg = if let Some(current) = self.current {
|
||||||
|
libc::CMSG_NXTHDR(&msg, current)
|
||||||
|
} else {
|
||||||
|
libc::CMSG_FIRSTHDR(&msg)
|
||||||
|
};
|
||||||
|
cmsg.as_ref()?
|
||||||
|
};
|
||||||
|
|
||||||
|
self.current = Some(cmsg);
|
||||||
|
CmsgData::try_from_cmsghdr(cmsg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> CMessages<'a> {
|
||||||
|
pub fn from_bytes(msg_control: &'a mut [u8]) -> Self {
|
||||||
|
Self {
|
||||||
|
buffer: msg_control,
|
||||||
|
current: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Control message data of variable type. The data resides next to `cmsghdr`.
|
||||||
|
pub enum CmsgData<'a> {
|
||||||
|
ScmRights(ScmRights<'a>),
|
||||||
|
ScmCredentials,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> CmsgData<'a> {
|
||||||
|
/// Create an `CmsgData::ScmRights` variant.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// `data` must contain a valid control message and the control message must be type of
|
||||||
|
/// `SOL_SOCKET` and level of `SCM_RIGHTS`.
|
||||||
|
unsafe fn as_rights(data: &'a mut [u8]) -> Self {
|
||||||
|
let scm_rights = ScmRights { data };
|
||||||
|
CmsgData::ScmRights(scm_rights)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create an `CmsgData::ScmCredentials` variant.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// `data` must contain a valid control message and the control message must be type of
|
||||||
|
/// `SOL_SOCKET` and level of `SCM_CREDENTIALS`.
|
||||||
|
unsafe fn as_credentials(_data: &'a [u8]) -> Self {
|
||||||
|
CmsgData::ScmCredentials
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_from_cmsghdr(cmsg: &'a libc::cmsghdr) -> Option<Self> {
|
||||||
|
unsafe {
|
||||||
|
let cmsg_len_zero = libc::CMSG_LEN(0) as usize;
|
||||||
|
let data_len = (*cmsg).cmsg_len as usize - cmsg_len_zero;
|
||||||
|
let data = libc::CMSG_DATA(cmsg);
|
||||||
|
let data = core::slice::from_raw_parts_mut(data, data_len);
|
||||||
|
|
||||||
|
match (*cmsg).cmsg_level {
|
||||||
|
libc::SOL_SOCKET => match (*cmsg).cmsg_type {
|
||||||
|
libc::SCM_RIGHTS => Some(CmsgData::as_rights(data)),
|
||||||
|
libc::SCM_CREDENTIALS => Some(CmsgData::as_credentials(data)),
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The data unit of this control message is file descriptor(s).
|
||||||
|
///
|
||||||
|
/// The level is equal to `SOL_SOCKET` and the type is equal to `SCM_RIGHTS`.
|
||||||
|
pub struct ScmRights<'a> {
|
||||||
|
data: &'a mut [u8],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ScmRights<'a> {
|
||||||
|
/// Iterate and reassign each fd in data buffer, given a reassignment function.
|
||||||
|
pub fn iter_and_reassign_fds<F>(&mut self, reassign_fd_fn: F)
|
||||||
|
where
|
||||||
|
F: Fn(FileDesc) -> FileDesc,
|
||||||
|
{
|
||||||
|
for fd_bytes in self.data.chunks_exact_mut(core::mem::size_of::<FileDesc>()) {
|
||||||
|
let old_fd = FileDesc::from_ne_bytes(fd_bytes.try_into().unwrap());
|
||||||
|
let reassigned_fd = reassign_fd_fn(old_fd);
|
||||||
|
fd_bytes.copy_from_slice(&reassigned_fd.to_ne_bytes());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter_fds(&self) -> impl Iterator<Item = FileDesc> + '_ {
|
||||||
|
self.data
|
||||||
|
.chunks_exact(core::mem::size_of::<FileDesc>())
|
||||||
|
.map(|fd_bytes| FileDesc::from_ne_bytes(fd_bytes.try_into().unwrap()))
|
||||||
|
}
|
||||||
|
}
|
34
src/libos/src/net/socket/util/protocol.rs
Normal file
34
src/libos/src/net/socket/util/protocol.rs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
use num_enum::{IntoPrimitive, TryFromPrimitive};
|
||||||
|
|
||||||
|
/* Standard well-defined IP protocols. */
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, IntoPrimitive, TryFromPrimitive)]
|
||||||
|
#[repr(i32)]
|
||||||
|
pub enum SocketProtocol {
|
||||||
|
IPPROTO_IP = 0, /* Dummy protocol for TCP. */
|
||||||
|
IPPROTO_ICMP = 1, /* Internet Control Message Protocol. */
|
||||||
|
IPPROTO_IGMP = 2, /* Internet Group Management Protocol. */
|
||||||
|
IPPROTO_IPIP = 4, /* IPIP tunnels (older KA9Q tunnels use 94). */
|
||||||
|
IPPROTO_TCP = 6, /* Transmission Control Protocol. */
|
||||||
|
IPPROTO_EGP = 8, /* Exterior Gateway Protocol. */
|
||||||
|
IPPROTO_PUP = 12, /* PUP protocol. */
|
||||||
|
IPPROTO_UDP = 17, /* User Datagram Protocol. */
|
||||||
|
IPPROTO_IDP = 22, /* XNS IDP protocol. */
|
||||||
|
IPPROTO_TP = 29, /* SO Transport Protocol Class 4. */
|
||||||
|
IPPROTO_DCCP = 33, /* Datagram Congestion Control Protocol. */
|
||||||
|
IPPROTO_IPV6 = 41, /* IPv6 header. */
|
||||||
|
IPPROTO_RSVP = 46, /* Reservation Protocol. */
|
||||||
|
IPPROTO_GRE = 47, /* General Routing Encapsulation. */
|
||||||
|
IPPROTO_ESP = 50, /* encapsulating security payload. */
|
||||||
|
IPPROTO_AH = 51, /* authentication header. */
|
||||||
|
IPPROTO_MTP = 92, /* Multicast Transport Protocol. */
|
||||||
|
IPPROTO_BEETPH = 94, /* IP option pseudo header for BEET. */
|
||||||
|
IPPROTO_ENCAP = 98, /* Encapsulation Header. */
|
||||||
|
IPPROTO_PIM = 103, /* Protocol Independent Multicast. */
|
||||||
|
IPPROTO_COMP = 108, /* Compression Header Protocol. */
|
||||||
|
IPPROTO_SCTP = 132, /* Stream Control Transmission Protocol. */
|
||||||
|
IPPROTO_UDPLITE = 136, /* UDP-Lite protocol. */
|
||||||
|
IPPROTO_MPLS = 137, /* MPLS in IP. */
|
||||||
|
IPPROTO_RAW = 255, /* Raw IP packets. */
|
||||||
|
IPPROTO_MAX,
|
||||||
|
}
|
34
src/libos/src/net/socket/util/shutdown.rs
Normal file
34
src/libos/src/net/socket/util/shutdown.rs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
#[repr(u32)]
|
||||||
|
pub enum Shutdown {
|
||||||
|
Read = 0,
|
||||||
|
Write = 1,
|
||||||
|
Both = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Shutdown {
|
||||||
|
pub fn from_c(c_val: u32) -> Result<Self> {
|
||||||
|
match c_val {
|
||||||
|
0 => Ok(Self::Read),
|
||||||
|
1 => Ok(Self::Write),
|
||||||
|
2 => Ok(Self::Both),
|
||||||
|
_ => return_errno!(EINVAL, "invalid how"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_c(&self) -> u32 {
|
||||||
|
*self as u32
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn should_shut_read(&self) -> bool {
|
||||||
|
// a slightly more efficient check than using two equality comparions
|
||||||
|
self.to_c() % 2 == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn should_shut_write(&self) -> bool {
|
||||||
|
// a slightly more efficient check than using two equality comparions
|
||||||
|
self.to_c() >= 1
|
||||||
|
}
|
||||||
|
}
|
15
src/libos/src/net/socket/util/type.rs
Normal file
15
src/libos/src/net/socket/util/type.rs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
use crate::prelude::*;
|
||||||
|
use num_enum::{IntoPrimitive, TryFromPrimitive};
|
||||||
|
|
||||||
|
/// A network type.
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, IntoPrimitive, TryFromPrimitive)]
|
||||||
|
#[repr(i32)]
|
||||||
|
pub enum Type {
|
||||||
|
STREAM = libc::SOCK_STREAM,
|
||||||
|
DGRAM = libc::SOCK_DGRAM,
|
||||||
|
RAW = libc::SOCK_RAW,
|
||||||
|
RDM = libc::SOCK_RDM,
|
||||||
|
SEQPACKET = libc::SOCK_SEQPACKET,
|
||||||
|
DCCP = libc::SOCK_DCCP,
|
||||||
|
PACKET = libc::SOCK_PACKET,
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user