[libos] Implement inner-defined sockopt with ioctl api
This commit is contained in:
parent
92ec7c334b
commit
9d4dcc2b21
@ -1,7 +1,7 @@
|
||||
use atomic::Atomic;
|
||||
use std::any::Any;
|
||||
use std::io::{Read, Seek, SeekFrom, Write};
|
||||
use std::mem;
|
||||
use atomic::Atomic;
|
||||
|
||||
use super::*;
|
||||
use crate::fs::{
|
||||
|
@ -1,14 +1,15 @@
|
||||
use std::any::Any;
|
||||
use std::io::{Read, Seek, SeekFrom, Write};
|
||||
|
||||
use atomic::{Atomic, Ordering};
|
||||
|
||||
use super::*;
|
||||
use crate::fs::{AccessMode, File, HostFd, IoEvents, StatusFlags, STATUS_FLAGS_MASK};
|
||||
use crate::fs::{
|
||||
AccessMode, AtomicIoEvents, File, HostFd, IoEvents, StatusFlags, STATUS_FLAGS_MASK,
|
||||
};
|
||||
use crate::fs::{
|
||||
GetIfConf, GetIfReqWithRawCmd, GetReadBufLen, IoctlCmd, NonBuiltinIoctlCmd, SetNonBlocking,
|
||||
};
|
||||
use crate::net::socket::sockopt::{GetSockOptRawCmd, SetSockOptRawCmd};
|
||||
use atomic::{Atomic, Ordering};
|
||||
|
||||
//TODO: refactor write syscall to allow zero length with non-zero buffer
|
||||
impl File for HostSocket {
|
||||
|
64
src/libos/src/net/socket/sockopt/get.rs
Normal file
64
src/libos/src/net/socket/sockopt/get.rs
Normal file
@ -0,0 +1,64 @@
|
||||
use crate::{fs::IoctlCmd, prelude::*};
|
||||
use libc::ocall::getsockopt as do_getsockopt;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct GetSockOptRawCmd {
|
||||
level: i32,
|
||||
optname: i32,
|
||||
optval: Box<[u8]>,
|
||||
optlen: Option<u32>,
|
||||
}
|
||||
|
||||
impl GetSockOptRawCmd {
|
||||
pub fn new(level: i32, optname: i32, max_optlen: u32) -> Self {
|
||||
// Using uninit slice is safe, since the buffer in rust SDK ocall is [out] type.
|
||||
let optval = unsafe { Box::new_uninit_slice(max_optlen as usize).assume_init() };
|
||||
Self {
|
||||
level,
|
||||
optname,
|
||||
optval,
|
||||
optlen: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn execute(&mut self, fd: FileDesc) -> Result<()> {
|
||||
if self.optlen.is_some() {
|
||||
return_errno!(EINVAL, "can not execute twice");
|
||||
}
|
||||
self.optlen = Some(getsockopt_by_host(
|
||||
fd,
|
||||
self.level,
|
||||
self.optname,
|
||||
&mut self.optval,
|
||||
)?);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn output(&self) -> Option<&[u8]> {
|
||||
self.optlen.map(|_| self.optval.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
impl IoctlCmd for GetSockOptRawCmd {}
|
||||
|
||||
pub fn getsockopt_by_host(
|
||||
fd: FileDesc,
|
||||
level: i32,
|
||||
optname: i32,
|
||||
optval: &mut [u8],
|
||||
) -> Result<u32> {
|
||||
let max_optlen = optval.len() as u32;
|
||||
let mut optlen = max_optlen;
|
||||
try_libc!(do_getsockopt(
|
||||
fd as _,
|
||||
level as _,
|
||||
optname as _,
|
||||
optval.as_mut_ptr() as _,
|
||||
&mut optlen as *mut u32
|
||||
));
|
||||
// Defence Iago attack
|
||||
if optlen > max_optlen {
|
||||
return_errno!(EINVAL, "host returns a invalid optlen");
|
||||
}
|
||||
Ok(optlen)
|
||||
}
|
3
src/libos/src/net/socket/sockopt/get_acceptconn.rs
Normal file
3
src/libos/src/net/socket/sockopt/get_acceptconn.rs
Normal file
@ -0,0 +1,3 @@
|
||||
crate::impl_ioctl_cmd! {
|
||||
pub struct GetAcceptConnCmd<Input=(), Output=i32> {}
|
||||
}
|
3
src/libos/src/net/socket/sockopt/get_domain.rs
Normal file
3
src/libos/src/net/socket/sockopt/get_domain.rs
Normal file
@ -0,0 +1,3 @@
|
||||
crate::impl_ioctl_cmd! {
|
||||
pub struct GetDomainCmd<Input=(), Output=i32> {}
|
||||
}
|
3
src/libos/src/net/socket/sockopt/get_error.rs
Normal file
3
src/libos/src/net/socket/sockopt/get_error.rs
Normal file
@ -0,0 +1,3 @@
|
||||
crate::impl_ioctl_cmd! {
|
||||
pub struct GetErrorCmd<Input=(), Output=i32> {}
|
||||
}
|
105
src/libos/src/net/socket/sockopt/get_output.rs
Normal file
105
src/libos/src/net/socket/sockopt/get_output.rs
Normal file
@ -0,0 +1,105 @@
|
||||
use super::{GetRecvTimeoutCmd, GetSendTimeoutCmd};
|
||||
|
||||
use super::{
|
||||
GetAcceptConnCmd, GetDomainCmd, GetErrorCmd, GetPeerNameCmd, GetRcvBufSizeCmd,
|
||||
GetSndBufSizeCmd, GetSockOptRawCmd, GetTypeCmd,
|
||||
};
|
||||
|
||||
use libc::timeval;
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
pub trait GetOutputAsBytes {
|
||||
fn get_output_as_bytes(&self) -> Option<&[u8]>;
|
||||
}
|
||||
|
||||
impl GetOutputAsBytes for GetSockOptRawCmd {
|
||||
fn get_output_as_bytes(&self) -> Option<&[u8]> {
|
||||
self.output()
|
||||
}
|
||||
}
|
||||
|
||||
impl GetOutputAsBytes for GetDomainCmd {
|
||||
fn get_output_as_bytes(&self) -> Option<&[u8]> {
|
||||
self.output().map(|val_ref| unsafe {
|
||||
std::slice::from_raw_parts(val_ref as *const _ as *const u8, std::mem::size_of::<i32>())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl GetOutputAsBytes for GetErrorCmd {
|
||||
fn get_output_as_bytes(&self) -> Option<&[u8]> {
|
||||
self.output().map(|val_ref| unsafe {
|
||||
std::slice::from_raw_parts(val_ref as *const _ as *const u8, std::mem::size_of::<i32>())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl GetOutputAsBytes for GetAcceptConnCmd {
|
||||
fn get_output_as_bytes(&self) -> Option<&[u8]> {
|
||||
self.output().map(|val_ref| unsafe {
|
||||
std::slice::from_raw_parts(val_ref as *const _ as *const u8, std::mem::size_of::<i32>())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl GetOutputAsBytes for GetPeerNameCmd {
|
||||
fn get_output_as_bytes(&self) -> Option<&[u8]> {
|
||||
self.output().map(|val_ref| unsafe {
|
||||
std::slice::from_raw_parts(&(val_ref.0).0 as *const _ as *const u8, (val_ref.0).1)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl GetOutputAsBytes for GetTypeCmd {
|
||||
fn get_output_as_bytes(&self) -> Option<&[u8]> {
|
||||
self.output().map(|val_ref| unsafe {
|
||||
std::slice::from_raw_parts(val_ref as *const _ as *const u8, std::mem::size_of::<i32>())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl GetOutputAsBytes for GetSndBufSizeCmd {
|
||||
fn get_output_as_bytes(&self) -> Option<&[u8]> {
|
||||
self.output().map(|val_ref| unsafe {
|
||||
std::slice::from_raw_parts(
|
||||
val_ref as *const _ as *const u8,
|
||||
std::mem::size_of::<usize>(),
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl GetOutputAsBytes for GetRcvBufSizeCmd {
|
||||
fn get_output_as_bytes(&self) -> Option<&[u8]> {
|
||||
self.output().map(|val_ref| unsafe {
|
||||
std::slice::from_raw_parts(
|
||||
val_ref as *const _ as *const u8,
|
||||
std::mem::size_of::<usize>(),
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl GetOutputAsBytes for GetRecvTimeoutCmd {
|
||||
fn get_output_as_bytes(&self) -> Option<&[u8]> {
|
||||
self.output().map(|val_ref| unsafe {
|
||||
std::slice::from_raw_parts(
|
||||
val_ref as *const _ as *const u8,
|
||||
std::mem::size_of::<timeval>(),
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl GetOutputAsBytes for GetSendTimeoutCmd {
|
||||
fn get_output_as_bytes(&self) -> Option<&[u8]> {
|
||||
self.output().map(|val_ref| unsafe {
|
||||
std::slice::from_raw_parts(
|
||||
val_ref as *const _ as *const u8,
|
||||
std::mem::size_of::<timeval>(),
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
15
src/libos/src/net/socket/sockopt/get_peername.rs
Normal file
15
src/libos/src/net/socket/sockopt/get_peername.rs
Normal file
@ -0,0 +1,15 @@
|
||||
use sgx_trts::libc;
|
||||
|
||||
pub struct AddrStorage(pub (libc::sockaddr_storage, usize));
|
||||
impl std::fmt::Debug for AddrStorage {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_tuple("AddrStorage")
|
||||
.field(&"sockaddr_storage")
|
||||
.field(&(self.0).1)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
crate::impl_ioctl_cmd! {
|
||||
pub struct GetPeerNameCmd<Input=(), Output=AddrStorage> {}
|
||||
}
|
7
src/libos/src/net/socket/sockopt/get_sockbuf.rs
Normal file
7
src/libos/src/net/socket/sockopt/get_sockbuf.rs
Normal file
@ -0,0 +1,7 @@
|
||||
crate::impl_ioctl_cmd! {
|
||||
pub struct GetSndBufSizeCmd<Input=(), Output=usize> {}
|
||||
}
|
||||
|
||||
crate::impl_ioctl_cmd! {
|
||||
pub struct GetRcvBufSizeCmd<Input=(), Output=usize> {}
|
||||
}
|
3
src/libos/src/net/socket/sockopt/get_type.rs
Normal file
3
src/libos/src/net/socket/sockopt/get_type.rs
Normal file
@ -0,0 +1,3 @@
|
||||
crate::impl_ioctl_cmd! {
|
||||
pub struct GetTypeCmd<Input=(), Output=i32> {}
|
||||
}
|
105
src/libos/src/net/socket/sockopt/mod.rs
Normal file
105
src/libos/src/net/socket/sockopt/mod.rs
Normal file
@ -0,0 +1,105 @@
|
||||
mod get;
|
||||
mod get_acceptconn;
|
||||
mod get_domain;
|
||||
mod get_error;
|
||||
mod get_output;
|
||||
mod get_peername;
|
||||
mod get_sockbuf;
|
||||
mod get_type;
|
||||
mod set;
|
||||
mod set_sockbuf;
|
||||
mod timeout;
|
||||
|
||||
pub use get::{getsockopt_by_host, GetSockOptRawCmd};
|
||||
pub use get_acceptconn::GetAcceptConnCmd;
|
||||
pub use get_domain::GetDomainCmd;
|
||||
pub use get_error::GetErrorCmd;
|
||||
pub use get_output::*;
|
||||
pub use get_peername::{AddrStorage, GetPeerNameCmd};
|
||||
pub use get_sockbuf::{GetRcvBufSizeCmd, GetSndBufSizeCmd};
|
||||
pub use get_type::GetTypeCmd;
|
||||
pub use set::{setsockopt_by_host, SetSockOptRawCmd};
|
||||
pub use set_sockbuf::{SetRcvBufSizeCmd, SetSndBufSizeCmd};
|
||||
pub use timeout::{
|
||||
timeout_to_timeval, GetRecvTimeoutCmd, GetSendTimeoutCmd, SetRecvTimeoutCmd, SetSendTimeoutCmd,
|
||||
};
|
||||
|
||||
use num_enum::{IntoPrimitive, TryFromPrimitive};
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, IntoPrimitive, TryFromPrimitive)]
|
||||
#[repr(i32)]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub enum SockOptName {
|
||||
SO_DEBUG = 1, // i32, bool, 0 or 1
|
||||
SO_REUSEADDR = 2, // i32, bool, 0 or 1
|
||||
SO_TYPE = 3, // [builtin] read-only, i32
|
||||
SO_ERROR = 4, // read-only, i32
|
||||
SO_DONTROUTE = 5, // i32, bool, 0 or 1, Equal to: send with MSG_DONTROUTE flag.
|
||||
SO_BROADCAST = 6, // i32, bool, 0 or 1
|
||||
SO_SNDBUF = 7, // i32
|
||||
SO_RCVBUF = 8, // i32
|
||||
SO_KEEPALIVE = 9, // i32, bool, 0 or 1
|
||||
SO_OOBINLINE = 10, // i32, bool, 0 or 1, Might equal to: recv with MSG_OOB flag.
|
||||
SO_NO_CHECK = 11, // i32, bool, 0 or 1
|
||||
SO_PRIORITY = 12, // i32, >= 0, <= 6
|
||||
SO_LINGER = 13, // linger structure
|
||||
SO_BSDCOMPAT = 14, // removed in linux 2.2
|
||||
SO_REUSEPORT = 15, // i32, bool, 0 or 1
|
||||
SO_PASSCRED = 16, // i32, bool, 0 or 1
|
||||
SO_PEERCRED = 17, // read-only, ucred structure
|
||||
// TODO: there may be a bug.
|
||||
// select(2), poll(2), and epoll(7) indicate a socket as readable
|
||||
// only if at least SO_RCVLOWAT bytes are available.
|
||||
SO_RCVLOWAT = 18, // i32
|
||||
SO_SNDLOWAT = 19, // read-only, i32
|
||||
SO_RCVTIMEO_OLD = 20, // struct timeval
|
||||
SO_SNDTIMEO_OLD = 21, // struct timeval
|
||||
SO_SECURITY_AUTHENTICATION = 22, // no doc / code
|
||||
SO_SECURITY_ENCRYPTION_TRANSPORT = 23, // no doc / code
|
||||
SO_SECURITY_ENCRYPTION_NETWORK = 24, // no doc / code
|
||||
SO_BINDTODEVICE = 25, // array
|
||||
SO_ATTACH_FILTER = 26, // SO_GET_FILTER, BPF-related
|
||||
SO_DETACH_FILTER = 27, // SO_DETACH_BPF, BPF-related
|
||||
SO_PEERNAME = 28, // [builtin] read-only, peer name
|
||||
SO_TIMESTAMP_OLD = 29, // i32, bool, 0 or 1, cmsg-related
|
||||
SO_ACCEPTCONN = 30, // [builtin] read-only, i32, bool, 0 or 1
|
||||
SO_PEERSEC = 31, // read-only, array
|
||||
SO_SNDBUFFORCE = 32, // i32
|
||||
SO_RCVBUFFORCE = 33, // i32
|
||||
SO_PASSSEC = 34, // i32, bool, 0 or 1, cmsg-related
|
||||
SO_TIMESTAMPNS_OLD = 35, // i32, bool, 0 or 1, cmsg-related
|
||||
SO_MARK = 36, // i32
|
||||
SO_TIMESTAMPING_OLD = 37, // i32, bool, 0 or 1, cmsg-related
|
||||
SO_PROTOCOL = 38, // read-only, i32
|
||||
SO_DOMAIN = 39, // [builtin] read-only, i32
|
||||
SO_RXQ_OVFL = 40, // i32, bool, 0 or 1, cmsg-related
|
||||
SO_WIFI_STATUS = 41, // i32, bool, 0 or 1
|
||||
// TODO: there may be a bug when specify SO_PEEK_OFF and MSG_PEEK
|
||||
SO_PEEK_OFF = 42, // i32
|
||||
SO_NOFCS = 43, // i32, bool, 0 or 1
|
||||
SO_LOCK_FILTER = 44, // i32, bool, 0 or 1
|
||||
SO_SELECT_ERR_QUEUE = 45, // i32, bool, 0 or 1
|
||||
SO_BUSY_POLL = 46, // i32
|
||||
SO_MAX_PACING_RATE = 47, // u64
|
||||
SO_BPF_EXTENSIONS = 48, // BPF-related
|
||||
SO_INCOMING_CPU = 49, // i32
|
||||
SO_ATTACH_BPF = 50, // BPF-related
|
||||
SO_ATTACH_REUSEPORT_CBPF = 51, // BPF-related
|
||||
SO_ATTACH_REUSEPORT_EBPF = 52, // BPF-related
|
||||
SO_CNX_ADVICE = 53, // write-only, i32
|
||||
SCM_TIMESTAMPING_OPT_STATS = 54, // no doc / code
|
||||
SO_MEMINFO = 55, // read-only, array
|
||||
SO_INCOMING_NAPI_ID = 56, // read-only, i32
|
||||
SO_COOKIE = 57, // read-only, u64
|
||||
SCM_TIMESTAMPING_PKTINFO = 58, // no doc / code
|
||||
SO_PEERGROUPS = 59, // read-only, array
|
||||
SO_ZEROCOPY = 60, // i32, bool, 0 or 1
|
||||
SO_TXTIME = 61, // SCM_TXTIME, struct sock_txtime
|
||||
SO_BINDTOIFINDEX = 62, // i32
|
||||
SO_TIMESTAMP_NEW = 63, // i32, bool, 0 or 1, cmsg-related
|
||||
SO_TIMESTAMPNS_NEW = 64, // i32, bool, 0 or 1, cmsg-related
|
||||
SO_TIMESTAMPING_NEW = 65, // i32, bool, 0 or 1, cmsg-related
|
||||
SO_RCVTIMEO_NEW = 66, // struct timeval
|
||||
SO_SNDTIMEO_NEW = 67, // struct timeval
|
||||
SO_DETACH_REUSEPORT_BPF = 68, // BPF-related
|
||||
}
|
38
src/libos/src/net/socket/sockopt/set.rs
Normal file
38
src/libos/src/net/socket/sockopt/set.rs
Normal file
@ -0,0 +1,38 @@
|
||||
use crate::{fs::IoctlCmd, prelude::*};
|
||||
use libc::ocall::setsockopt as do_setsockopt;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SetSockOptRawCmd {
|
||||
level: i32,
|
||||
optname: i32,
|
||||
optval: Box<[u8]>,
|
||||
}
|
||||
|
||||
impl SetSockOptRawCmd {
|
||||
pub fn new(level: i32, optname: i32, optval: &[u8]) -> Self {
|
||||
let optval = Box::from(optval);
|
||||
Self {
|
||||
level,
|
||||
optname,
|
||||
optval,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn execute(&mut self, fd: FileDesc) -> Result<()> {
|
||||
setsockopt_by_host(fd, self.level, self.optname, &self.optval)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl IoctlCmd for SetSockOptRawCmd {}
|
||||
|
||||
pub fn setsockopt_by_host(fd: FileDesc, level: i32, optname: i32, optval: &[u8]) -> Result<()> {
|
||||
try_libc!(do_setsockopt(
|
||||
fd as _,
|
||||
level as _,
|
||||
optname as _,
|
||||
optval.as_ptr() as _,
|
||||
optval.len() as _
|
||||
));
|
||||
Ok(())
|
||||
}
|
62
src/libos/src/net/socket/sockopt/set_sockbuf.rs
Normal file
62
src/libos/src/net/socket/sockopt/set_sockbuf.rs
Normal file
@ -0,0 +1,62 @@
|
||||
use super::set::setsockopt_by_host;
|
||||
use crate::{fs::IoctlCmd, prelude::*};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SetSndBufSizeCmd {
|
||||
buf_size: usize,
|
||||
}
|
||||
|
||||
impl SetSndBufSizeCmd {
|
||||
pub fn new(buf_size: usize) -> Self {
|
||||
Self { buf_size }
|
||||
}
|
||||
|
||||
pub fn buf_size(&self) -> usize {
|
||||
self.buf_size
|
||||
}
|
||||
|
||||
pub fn update_host(&self, fd: FileDesc) -> Result<()> {
|
||||
// The buf size for host call should be divided by 2 because the value will be doubled by host kernel.
|
||||
let host_call_buf_size = (self.buf_size / 2).to_ne_bytes();
|
||||
|
||||
// Setting SO_SNDBUF for host socket needs to respect /proc/sys/net/core/wmem_max. Thus, the value might be different on host, but it is fine.
|
||||
setsockopt_by_host(
|
||||
fd,
|
||||
libc::SOL_SOCKET,
|
||||
super::SockOptName::SO_SNDBUF.into(),
|
||||
&host_call_buf_size,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl IoctlCmd for SetSndBufSizeCmd {}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SetRcvBufSizeCmd {
|
||||
buf_size: usize,
|
||||
}
|
||||
|
||||
impl SetRcvBufSizeCmd {
|
||||
pub fn new(buf_size: usize) -> Self {
|
||||
Self { buf_size }
|
||||
}
|
||||
|
||||
pub fn buf_size(&self) -> usize {
|
||||
self.buf_size
|
||||
}
|
||||
|
||||
pub fn update_host(&self, fd: FileDesc) -> Result<()> {
|
||||
// The buf size for host call should be divided by 2 because the value will be doubled by host kernel.
|
||||
let host_call_buf_size = (self.buf_size / 2).to_ne_bytes();
|
||||
|
||||
// Setting SO_RCVBUF for host socket needs to respect /proc/sys/net/core/rmem_max. Thus, the value might be different on host, but it is fine.
|
||||
setsockopt_by_host(
|
||||
fd,
|
||||
libc::SOL_SOCKET,
|
||||
super::SockOptName::SO_RCVBUF.into(),
|
||||
&host_call_buf_size,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl IoctlCmd for SetRcvBufSizeCmd {}
|
65
src/libos/src/net/socket/sockopt/timeout.rs
Normal file
65
src/libos/src/net/socket/sockopt/timeout.rs
Normal file
@ -0,0 +1,65 @@
|
||||
use crate::fs::IoctlCmd;
|
||||
use crate::prelude::*;
|
||||
use libc::{suseconds_t, time_t};
|
||||
use std::time::Duration;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SetSendTimeoutCmd(Duration);
|
||||
|
||||
impl IoctlCmd for SetSendTimeoutCmd {}
|
||||
|
||||
impl SetSendTimeoutCmd {
|
||||
pub fn new(timeout: Duration) -> Self {
|
||||
Self(timeout)
|
||||
}
|
||||
|
||||
pub fn timeout(&self) -> &Duration {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SetRecvTimeoutCmd(Duration);
|
||||
|
||||
impl IoctlCmd for SetRecvTimeoutCmd {}
|
||||
|
||||
impl SetRecvTimeoutCmd {
|
||||
pub fn new(timeout: Duration) -> Self {
|
||||
Self(timeout)
|
||||
}
|
||||
|
||||
pub fn timeout(&self) -> &Duration {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
crate::impl_ioctl_cmd! {
|
||||
pub struct GetSendTimeoutCmd<Input=(), Output=timeval> {}
|
||||
}
|
||||
|
||||
crate::impl_ioctl_cmd! {
|
||||
pub struct GetRecvTimeoutCmd<Input=(), Output=timeval> {}
|
||||
}
|
||||
|
||||
pub fn timeout_to_timeval(timeout: Option<Duration>) -> timeval {
|
||||
match timeout {
|
||||
Some(duration) => {
|
||||
let sec = duration.as_secs();
|
||||
let usec = duration.subsec_micros();
|
||||
timeval {
|
||||
sec: sec as time_t,
|
||||
usec: usec as suseconds_t,
|
||||
}
|
||||
}
|
||||
None => timeval { sec: 0, usec: 0 },
|
||||
}
|
||||
}
|
||||
|
||||
// Same as libc::timeval
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub struct timeval {
|
||||
sec: time_t,
|
||||
usec: suseconds_t,
|
||||
}
|
Loading…
Reference in New Issue
Block a user