mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 18:26:48 +00:00
640 lines
21 KiB
Rust
640 lines
21 KiB
Rust
use core::{cmp::min, ffi::CStr};
|
||
|
||
use acpi::address;
|
||
use alloc::{boxed::Box, sync::Arc};
|
||
use log::debug;
|
||
use num_traits::{FromPrimitive, ToPrimitive};
|
||
use smoltcp::wire;
|
||
use system_error::SystemError::{self, *};
|
||
|
||
use crate::{
|
||
filesystem::vfs::{
|
||
file::{File, FileMode},
|
||
syscall::{IoVec, IoVecs},
|
||
FileType,
|
||
},
|
||
libs::spinlock::SpinLockGuard,
|
||
mm::{verify_area, VirtAddr},
|
||
// net::socket::{netlink::af_netlink::NetlinkSock, AddressFamily},
|
||
process::ProcessManager,
|
||
syscall::Syscall,
|
||
};
|
||
|
||
use super::socket::{self, Endpoint, Socket};
|
||
use super::socket::{netlink::endpoint, unix::Unix, AddressFamily as AF};
|
||
|
||
pub use super::syscall_util::*;
|
||
|
||
/// Flags for socket, socketpair, accept4
|
||
const SOCK_CLOEXEC: FileMode = FileMode::O_CLOEXEC;
|
||
const SOCK_NONBLOCK: FileMode = FileMode::O_NONBLOCK;
|
||
|
||
impl Syscall {
|
||
/// @brief sys_socket系统调用的实际执行函数
|
||
///
|
||
/// @param address_family 地址族
|
||
/// @param socket_type socket类型
|
||
/// @param protocol 传输协议
|
||
pub fn socket(
|
||
address_family: usize,
|
||
socket_type: usize,
|
||
protocol: usize,
|
||
) -> Result<usize, SystemError> {
|
||
// 打印收到的参数
|
||
// log::debug!(
|
||
// "socket: address_family={:?}, socket_type={:?}, protocol={:?}",
|
||
// address_family,
|
||
// socket_type,
|
||
// protocol
|
||
// );
|
||
let address_family = socket::AddressFamily::try_from(address_family as u16)?;
|
||
let type_arg = SysArgSocketType::from_bits_truncate(socket_type as u32);
|
||
let is_nonblock = type_arg.is_nonblock();
|
||
let is_close_on_exec = type_arg.is_cloexec();
|
||
let stype = socket::Type::try_from(type_arg)?;
|
||
// log::debug!("type_arg {:?} stype {:?}", type_arg, stype);
|
||
|
||
let inode = socket::create_socket(
|
||
address_family,
|
||
stype,
|
||
protocol as u32,
|
||
is_nonblock,
|
||
is_close_on_exec,
|
||
)?;
|
||
|
||
let file = File::new(inode, FileMode::O_RDWR)?;
|
||
// 把socket添加到当前进程的文件描述符表中
|
||
let binding = ProcessManager::current_pcb().fd_table();
|
||
let mut fd_table_guard = binding.write();
|
||
let fd: Result<usize, SystemError> =
|
||
fd_table_guard.alloc_fd(file, None).map(|x| x as usize);
|
||
drop(fd_table_guard);
|
||
return fd;
|
||
}
|
||
|
||
/// # sys_socketpair系统调用的实际执行函数
|
||
///
|
||
/// ## 参数
|
||
/// - `address_family`: 地址族
|
||
/// - `socket_type`: socket类型
|
||
/// - `protocol`: 传输协议
|
||
/// - `fds`: 用于返回文件描述符的数组
|
||
pub fn socketpair(
|
||
address_family: usize,
|
||
socket_type: usize,
|
||
protocol: usize,
|
||
fds: &mut [i32],
|
||
) -> Result<usize, SystemError> {
|
||
let address_family = AF::try_from(address_family as u16)?;
|
||
let socket_type = SysArgSocketType::from_bits_truncate(socket_type as u32);
|
||
let stype = socket::Type::try_from(socket_type)?;
|
||
|
||
let binding = ProcessManager::current_pcb().fd_table();
|
||
let mut fd_table_guard = binding.write();
|
||
|
||
// check address family, only support AF_UNIX
|
||
if address_family != AF::Unix {
|
||
return Err(SystemError::EAFNOSUPPORT);
|
||
}
|
||
|
||
// 创建一对socket
|
||
// let inode0 = socket::create_socket(
|
||
// address_family,
|
||
// stype,
|
||
// protocol as u32,
|
||
// socket_type.is_nonblock(),
|
||
// socket_type.is_cloexec(),
|
||
// )?;
|
||
// let inode1 = socket::create_socket(
|
||
// address_family,
|
||
// stype,
|
||
// protocol as u32,
|
||
// socket_type.is_nonblock(),
|
||
// socket_type.is_cloexec(),
|
||
// )?;
|
||
|
||
// // 进行pair
|
||
// unsafe {
|
||
// inode0.connect(socket::Endpoint::Inode(inode1.clone()))?;
|
||
// inode1.connect(socket::Endpoint::Inode(inode0.clone()))?;
|
||
// }
|
||
|
||
// 创建一对新的unix socket pair
|
||
let (inode0, inode1) = Unix::new_pairs(stype)?;
|
||
|
||
fds[0] = fd_table_guard.alloc_fd(File::new(inode0, FileMode::O_RDWR)?, None)?;
|
||
fds[1] = fd_table_guard.alloc_fd(File::new(inode1, FileMode::O_RDWR)?, None)?;
|
||
|
||
drop(fd_table_guard);
|
||
Ok(0)
|
||
}
|
||
|
||
/// @brief sys_setsockopt系统调用的实际执行函数
|
||
///
|
||
/// @param fd 文件描述符
|
||
/// @param level 选项级别
|
||
/// @param optname 选项名称
|
||
/// @param optval 选项值
|
||
/// @param optlen optval缓冲区长度
|
||
pub fn setsockopt(
|
||
fd: usize,
|
||
level: usize,
|
||
optname: usize,
|
||
optval: &[u8],
|
||
) -> Result<usize, SystemError> {
|
||
let sol = socket::OptionsLevel::try_from(level as u32)?;
|
||
let socket: Arc<socket::Inode> = ProcessManager::current_pcb()
|
||
.get_socket(fd as i32)
|
||
.ok_or(SystemError::EBADF)?;
|
||
debug!("setsockopt: level={:?}", level);
|
||
return socket.set_option(sol, optname, optval).map(|_| 0);
|
||
}
|
||
|
||
/// @brief sys_getsockopt系统调用的实际执行函数
|
||
///
|
||
/// 参考:https://man7.org/linux/man-pages/man2/setsockopt.2.html
|
||
///
|
||
/// @param fd 文件描述符
|
||
/// @param level 选项级别
|
||
/// @param optname 选项名称
|
||
/// @param optval 返回的选项值
|
||
/// @param optlen 返回的optval缓冲区长度
|
||
pub fn getsockopt(
|
||
fd: usize,
|
||
level: usize,
|
||
optname: usize,
|
||
optval: *mut u8,
|
||
optlen: *mut u32,
|
||
) -> Result<usize, SystemError> {
|
||
// 获取socket
|
||
let optval = optval as *mut u32;
|
||
let socket: Arc<socket::Inode> = ProcessManager::current_pcb()
|
||
.get_socket(fd as i32)
|
||
.ok_or(EBADF)?;
|
||
|
||
let level = socket::OptionsLevel::try_from(level as u32)?;
|
||
|
||
use socket::Options as SO;
|
||
use socket::OptionsLevel as SOL;
|
||
if matches!(level, SOL::SOCKET) {
|
||
let optname = SO::try_from(optname as u32).map_err(|_| ENOPROTOOPT)?;
|
||
match optname {
|
||
SO::SNDBUF => {
|
||
// 返回发送缓冲区大小
|
||
unsafe {
|
||
*optval = socket.send_buffer_size() as u32;
|
||
*optlen = core::mem::size_of::<u32>() as u32;
|
||
}
|
||
return Ok(0);
|
||
}
|
||
SO::RCVBUF => {
|
||
// 返回默认的接收缓冲区大小
|
||
unsafe {
|
||
*optval = socket.recv_buffer_size() as u32;
|
||
*optlen = core::mem::size_of::<u32>() as u32;
|
||
}
|
||
return Ok(0);
|
||
}
|
||
_ => {
|
||
return Err(ENOPROTOOPT);
|
||
}
|
||
}
|
||
}
|
||
drop(socket);
|
||
|
||
// To manipulate options at any other level the
|
||
// protocol number of the appropriate protocol controlling the
|
||
// option is supplied. For example, to indicate that an option is
|
||
// to be interpreted by the TCP protocol, level should be set to the
|
||
// protocol number of TCP.
|
||
|
||
if matches!(level, SOL::TCP) {
|
||
let optname =
|
||
PosixTcpSocketOptions::try_from(optname as i32).map_err(|_| ENOPROTOOPT)?;
|
||
match optname {
|
||
PosixTcpSocketOptions::Congestion => return Ok(0),
|
||
_ => {
|
||
return Err(ENOPROTOOPT);
|
||
}
|
||
}
|
||
}
|
||
return Err(ENOPROTOOPT);
|
||
}
|
||
|
||
/// @brief sys_connect系统调用的实际执行函数
|
||
///
|
||
/// @param fd 文件描述符
|
||
/// @param addr SockAddr
|
||
/// @param addrlen 地址长度
|
||
///
|
||
/// @return 成功返回0,失败返回错误码
|
||
pub fn connect(fd: usize, addr: *const SockAddr, addrlen: u32) -> Result<usize, SystemError> {
|
||
let endpoint: Endpoint = SockAddr::to_endpoint(addr, addrlen)?;
|
||
let socket: Arc<socket::Inode> = ProcessManager::current_pcb()
|
||
.get_socket(fd as i32)
|
||
.ok_or(SystemError::EBADF)?;
|
||
socket.connect(endpoint)?;
|
||
Ok(0)
|
||
}
|
||
|
||
/// @brief sys_bind系统调用的实际执行函数
|
||
///
|
||
/// @param fd 文件描述符
|
||
/// @param addr SockAddr
|
||
/// @param addrlen 地址长度
|
||
///
|
||
/// @return 成功返回0,失败返回错误码
|
||
pub fn bind(fd: usize, addr: *const SockAddr, addrlen: u32) -> Result<usize, SystemError> {
|
||
// 打印收到的参数
|
||
// log::debug!(
|
||
// "bind: fd={:?}, family={:?}, addrlen={:?}",
|
||
// fd,
|
||
// (unsafe { addr.as_ref().unwrap().family }),
|
||
// addrlen
|
||
// );
|
||
let endpoint: Endpoint = SockAddr::to_endpoint(addr, addrlen)?;
|
||
let socket: Arc<socket::Inode> = ProcessManager::current_pcb()
|
||
.get_socket(fd as i32)
|
||
.ok_or(SystemError::EBADF)?;
|
||
// log::debug!("bind: socket={:?}", socket);
|
||
socket.bind(endpoint)?;
|
||
Ok(0)
|
||
}
|
||
|
||
/// @brief sys_sendto系统调用的实际执行函数
|
||
///
|
||
/// @param fd 文件描述符
|
||
/// @param buf 发送缓冲区
|
||
/// @param flags 标志
|
||
/// @param addr SockAddr
|
||
/// @param addrlen 地址长度
|
||
///
|
||
/// @return 成功返回发送的字节数,失败返回错误码
|
||
pub fn sendto(
|
||
fd: usize,
|
||
buf: &[u8],
|
||
flags: u32,
|
||
addr: *const SockAddr,
|
||
addrlen: u32,
|
||
) -> Result<usize, SystemError> {
|
||
let endpoint = if addr.is_null() {
|
||
None
|
||
} else {
|
||
Some(SockAddr::to_endpoint(addr, addrlen)?)
|
||
};
|
||
|
||
let flags = socket::MessageFlag::from_bits_truncate(flags);
|
||
|
||
let socket: Arc<socket::Inode> = ProcessManager::current_pcb()
|
||
.get_socket(fd as i32)
|
||
.ok_or(SystemError::EBADF)?;
|
||
|
||
if let Some(endpoint) = endpoint {
|
||
return socket.send_to(buf, endpoint, flags);
|
||
} else {
|
||
return socket.send(buf, flags);
|
||
}
|
||
}
|
||
|
||
/// @brief sys_recvfrom系统调用的实际执行函数
|
||
///
|
||
/// @param fd 文件描述符
|
||
/// @param buf 接收缓冲区
|
||
/// @param flags 标志
|
||
/// @param addr SockAddr
|
||
/// @param addrlen 地址长度
|
||
///
|
||
/// @return 成功返回接收的字节数,失败返回错误码
|
||
pub fn recvfrom(
|
||
fd: usize,
|
||
buf: &mut [u8],
|
||
flags: u32,
|
||
addr: *mut SockAddr,
|
||
addr_len: *mut u32,
|
||
) -> Result<usize, SystemError> {
|
||
let socket: Arc<socket::Inode> = ProcessManager::current_pcb()
|
||
.get_socket(fd as i32)
|
||
.ok_or(SystemError::EBADF)?;
|
||
let flags = socket::MessageFlag::from_bits_truncate(flags);
|
||
|
||
if addr.is_null() {
|
||
let (n, _) = socket.recv_from(buf, flags, None)?;
|
||
return Ok(n);
|
||
}
|
||
|
||
// address is not null
|
||
let address = unsafe { addr.as_ref() }.ok_or(EINVAL)?;
|
||
|
||
if unsafe { address.is_empty() } {
|
||
let (recv_len, endpoint) = socket.recv_from(buf, flags, None)?;
|
||
let sockaddr_in = SockAddr::from(endpoint);
|
||
unsafe {
|
||
sockaddr_in.write_to_user(addr, addr_len)?;
|
||
}
|
||
return Ok(recv_len);
|
||
} else {
|
||
// 从socket中读取数据
|
||
let addr_len = *unsafe { addr_len.as_ref() }.ok_or(EINVAL)?;
|
||
let address = SockAddr::to_endpoint(addr, addr_len)?;
|
||
let (recv_len, _) = socket.recv_from(buf, flags, Some(address))?;
|
||
return Ok(recv_len);
|
||
};
|
||
}
|
||
|
||
/// @brief sys_recvmsg系统调用的实际执行函数
|
||
///
|
||
/// @param fd 文件描述符
|
||
/// @param msg MsgHdr
|
||
/// @param flags 标志,暂时未使用
|
||
///
|
||
/// @return 成功返回接收的字节数,失败返回错误码
|
||
pub fn recvmsg(fd: usize, msg: &mut MsgHdr, flags: u32) -> Result<usize, SystemError> {
|
||
todo!("recvmsg, fd={}, msg={:?}, flags={}", fd, msg, flags);
|
||
// // 检查每个缓冲区地址是否合法,生成iovecs
|
||
// let mut iovs = unsafe { IoVecs::from_user(msg.msg_iov, msg.msg_iovlen, true)? };
|
||
|
||
// let socket: Arc<socket::Inode> = ProcessManager::current_pcb()
|
||
// .get_socket(fd as i32)
|
||
// .ok_or(SystemError::EBADF)?;
|
||
|
||
// let flags = socket::MessageFlag::from_bits_truncate(flags as u32);
|
||
|
||
// let mut buf = iovs.new_buf(true);
|
||
// // 从socket中读取数据
|
||
// let recv_size = socket.recv_msg(&mut buf, flags)?;
|
||
// drop(socket);
|
||
|
||
// // 将数据写入用户空间的iovecs
|
||
// iovs.scatter(&buf[..recv_size]);
|
||
|
||
// // let sockaddr_in = SockAddr::from(endpoint);
|
||
// // unsafe {
|
||
// // sockaddr_in.write_to_user(msg.msg_name, &mut msg.msg_namelen)?;
|
||
// // }
|
||
// return Ok(recv_size);
|
||
}
|
||
|
||
/// @brief sys_listen系统调用的实际执行函数
|
||
///
|
||
/// @param fd 文件描述符
|
||
/// @param backlog 队列最大连接数
|
||
///
|
||
/// @return 成功返回0,失败返回错误码
|
||
pub fn listen(fd: usize, backlog: usize) -> Result<usize, SystemError> {
|
||
let socket: Arc<socket::Inode> = ProcessManager::current_pcb()
|
||
.get_socket(fd as i32)
|
||
.ok_or(SystemError::EBADF)?;
|
||
socket.listen(backlog).map(|_| 0)
|
||
}
|
||
|
||
/// @brief sys_shutdown系统调用的实际执行函数
|
||
///
|
||
/// @param fd 文件描述符
|
||
/// @param how 关闭方式
|
||
///
|
||
/// @return 成功返回0,失败返回错误码
|
||
pub fn shutdown(fd: usize, how: usize) -> Result<usize, SystemError> {
|
||
let socket: Arc<socket::Inode> = ProcessManager::current_pcb()
|
||
.get_socket(fd as i32)
|
||
.ok_or(SystemError::EBADF)?;
|
||
socket.shutdown(socket::ShutdownTemp::from_how(how))?;
|
||
return Ok(0);
|
||
}
|
||
|
||
/// @brief sys_accept系统调用的实际执行函数
|
||
///
|
||
/// @param fd 文件描述符
|
||
/// @param addr SockAddr
|
||
/// @param addrlen 地址长度
|
||
///
|
||
/// @return 成功返回新的文件描述符,失败返回错误码
|
||
pub fn accept(fd: usize, addr: *mut SockAddr, addrlen: *mut u32) -> Result<usize, SystemError> {
|
||
return Self::do_accept(fd, addr, addrlen, 0);
|
||
}
|
||
|
||
/// sys_accept4 - accept a connection on a socket
|
||
///
|
||
///
|
||
/// If flags is 0, then accept4() is the same as accept(). The
|
||
/// following values can be bitwise ORed in flags to obtain different
|
||
/// behavior:
|
||
///
|
||
/// - SOCK_NONBLOCK
|
||
/// Set the O_NONBLOCK file status flag on the open file
|
||
/// description (see open(2)) referred to by the new file
|
||
/// descriptor. Using this flag saves extra calls to fcntl(2)
|
||
/// to achieve the same result.
|
||
///
|
||
/// - SOCK_CLOEXEC
|
||
/// Set the close-on-exec (FD_CLOEXEC) flag on the new file
|
||
/// descriptor. See the description of the O_CLOEXEC flag in
|
||
/// open(2) for reasons why this may be useful.
|
||
pub fn accept4(
|
||
fd: usize,
|
||
addr: *mut SockAddr,
|
||
addrlen: *mut u32,
|
||
mut flags: u32,
|
||
) -> Result<usize, SystemError> {
|
||
// 如果flags不合法,返回错误
|
||
if (flags & (!(SOCK_CLOEXEC | SOCK_NONBLOCK)).bits()) != 0 {
|
||
return Err(SystemError::EINVAL);
|
||
}
|
||
|
||
if SOCK_NONBLOCK != FileMode::O_NONBLOCK && ((flags & SOCK_NONBLOCK.bits()) != 0) {
|
||
flags = (flags & !FileMode::O_NONBLOCK.bits()) | FileMode::O_NONBLOCK.bits();
|
||
}
|
||
|
||
return Self::do_accept(fd, addr, addrlen, flags);
|
||
}
|
||
|
||
fn do_accept(
|
||
fd: usize,
|
||
addr: *mut SockAddr,
|
||
addrlen: *mut u32,
|
||
flags: u32,
|
||
) -> Result<usize, SystemError> {
|
||
let socket: Arc<socket::Inode> = ProcessManager::current_pcb()
|
||
.get_socket(fd as i32)
|
||
.ok_or(SystemError::EBADF)?;
|
||
|
||
// 从socket中接收连接
|
||
let (new_socket, remote_endpoint) = socket.accept()?;
|
||
drop(socket);
|
||
|
||
// debug!("accept: new_socket={:?}", new_socket);
|
||
// Insert the new socket into the file descriptor vector
|
||
|
||
let mut file_mode = FileMode::O_RDWR;
|
||
if flags & SOCK_NONBLOCK.bits() != 0 {
|
||
file_mode |= FileMode::O_NONBLOCK;
|
||
}
|
||
if flags & SOCK_CLOEXEC.bits() != 0 {
|
||
file_mode |= FileMode::O_CLOEXEC;
|
||
}
|
||
|
||
let new_fd = ProcessManager::current_pcb()
|
||
.fd_table()
|
||
.write()
|
||
.alloc_fd(File::new(new_socket, file_mode)?, None)?;
|
||
// debug!("accept: new_fd={}", new_fd);
|
||
if !addr.is_null() {
|
||
// debug!("accept: write remote_endpoint to user");
|
||
// 将对端地址写入用户空间
|
||
let sockaddr_in = SockAddr::from(remote_endpoint);
|
||
unsafe {
|
||
sockaddr_in.write_to_user(addr, addrlen)?;
|
||
}
|
||
}
|
||
return Ok(new_fd as usize);
|
||
}
|
||
|
||
/// @brief sys_getsockname系统调用的实际执行函数
|
||
///
|
||
/// Returns the current address to which the socket
|
||
/// sockfd is bound, in the buffer pointed to by addr.
|
||
///
|
||
/// @param fd 文件描述符
|
||
/// @param addr SockAddr
|
||
/// @param addrlen 地址长度
|
||
///
|
||
/// @return 成功返回0,失败返回错误码
|
||
pub fn getsockname(
|
||
fd: usize,
|
||
addr: *mut SockAddr,
|
||
addrlen: *mut u32,
|
||
) -> Result<usize, SystemError> {
|
||
if addr.is_null() {
|
||
return Err(SystemError::EINVAL);
|
||
}
|
||
let endpoint = ProcessManager::current_pcb()
|
||
.get_socket(fd as i32)
|
||
.ok_or(SystemError::EBADF)?
|
||
.get_name()?;
|
||
|
||
let sockaddr_in = SockAddr::from(endpoint);
|
||
unsafe {
|
||
sockaddr_in.write_to_user(addr, addrlen)?;
|
||
}
|
||
return Ok(0);
|
||
}
|
||
|
||
/// @brief sys_getpeername系统调用的实际执行函数
|
||
///
|
||
/// @param fd 文件描述符
|
||
/// @param addr SockAddr
|
||
/// @param addrlen 地址长度
|
||
///
|
||
/// @return 成功返回0,失败返回错误码
|
||
pub fn getpeername(
|
||
fd: usize,
|
||
addr: *mut SockAddr,
|
||
addrlen: *mut u32,
|
||
) -> Result<usize, SystemError> {
|
||
if addr.is_null() {
|
||
return Err(SystemError::EINVAL);
|
||
}
|
||
|
||
let socket: Arc<socket::Inode> = ProcessManager::current_pcb()
|
||
.get_socket(fd as i32)
|
||
.ok_or(SystemError::EBADF)?;
|
||
|
||
let endpoint: Endpoint = socket.get_peer_name()?;
|
||
drop(socket);
|
||
|
||
let sockaddr_in = SockAddr::from(endpoint);
|
||
unsafe {
|
||
sockaddr_in.write_to_user(addr, addrlen)?;
|
||
}
|
||
return Ok(0);
|
||
}
|
||
}
|
||
|
||
#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)]
|
||
pub enum PosixTcpSocketOptions {
|
||
/// Turn off Nagle's algorithm.
|
||
NoDelay = 1,
|
||
/// Limit MSS.
|
||
MaxSegment = 2,
|
||
/// Never send partially complete segments.
|
||
Cork = 3,
|
||
/// Start keeplives after this period.
|
||
KeepIdle = 4,
|
||
/// Interval between keepalives.
|
||
KeepIntvl = 5,
|
||
/// Number of keepalives before death.
|
||
KeepCnt = 6,
|
||
/// Number of SYN retransmits.
|
||
Syncnt = 7,
|
||
/// Lifetime for orphaned FIN-WAIT-2 state.
|
||
Linger2 = 8,
|
||
/// Wake up listener only when data arrive.
|
||
DeferAccept = 9,
|
||
/// Bound advertised window
|
||
WindowClamp = 10,
|
||
/// Information about this connection.
|
||
Info = 11,
|
||
/// Block/reenable quick acks.
|
||
QuickAck = 12,
|
||
/// Congestion control algorithm.
|
||
Congestion = 13,
|
||
/// TCP MD5 Signature (RFC2385).
|
||
Md5Sig = 14,
|
||
/// Use linear timeouts for thin streams
|
||
ThinLinearTimeouts = 16,
|
||
/// Fast retrans. after 1 dupack.
|
||
ThinDupack = 17,
|
||
/// How long for loss retry before timeout.
|
||
UserTimeout = 18,
|
||
/// TCP sock is under repair right now.
|
||
Repair = 19,
|
||
RepairQueue = 20,
|
||
QueueSeq = 21,
|
||
RepairOptions = 22,
|
||
/// Enable FastOpen on listeners
|
||
FastOpen = 23,
|
||
Timestamp = 24,
|
||
/// Limit number of unsent bytes in write queue.
|
||
NotSentLowat = 25,
|
||
/// Get Congestion Control (optional) info.
|
||
CCInfo = 26,
|
||
/// Record SYN headers for new connections.
|
||
SaveSyn = 27,
|
||
/// Get SYN headers recorded for connection.
|
||
SavedSyn = 28,
|
||
/// Get/set window parameters.
|
||
RepairWindow = 29,
|
||
/// Attempt FastOpen with connect.
|
||
FastOpenConnect = 30,
|
||
/// Attach a ULP to a TCP connection.
|
||
ULP = 31,
|
||
/// TCP MD5 Signature with extensions.
|
||
Md5SigExt = 32,
|
||
/// Set the key for Fast Open(cookie).
|
||
FastOpenKey = 33,
|
||
/// Enable TFO without a TFO cookie.
|
||
FastOpenNoCookie = 34,
|
||
ZeroCopyReceive = 35,
|
||
/// Notify bytes available to read as a cmsg on read.
|
||
/// 与TCP_CM_INQ相同
|
||
INQ = 36,
|
||
/// delay outgoing packets by XX usec
|
||
TxDelay = 37,
|
||
}
|
||
|
||
impl TryFrom<i32> for PosixTcpSocketOptions {
|
||
type Error = SystemError;
|
||
|
||
fn try_from(value: i32) -> Result<Self, Self::Error> {
|
||
match <Self as FromPrimitive>::from_i32(value) {
|
||
Some(p) => Ok(p),
|
||
None => Err(SystemError::EINVAL),
|
||
}
|
||
}
|
||
}
|
||
|
||
impl From<PosixTcpSocketOptions> for i32 {
|
||
fn from(val: PosixTcpSocketOptions) -> Self {
|
||
<PosixTcpSocketOptions as ToPrimitive>::to_i32(&val).unwrap()
|
||
}
|
||
}
|