libc: partially sync ygglibc with socket changes

This commit is contained in:
Mark Poliakov 2025-02-18 23:51:07 +02:00
parent c2cf314dcd
commit 0105be8fea
4 changed files with 204 additions and 154 deletions

View File

@ -1,13 +1,30 @@
use core::{ffi::{c_int, c_void}, mem::MaybeUninit, ptr::{null, null_mut}};
use core::{
ffi::{c_int, c_void},
net::SocketAddr,
ptr::{null, null_mut},
};
use yggdrasil_abi::{
abi_serde::wire,
net::{MessageHeader, MessageHeaderMut},
};
use yggdrasil_rt::{io::RawFd, sys as syscall};
use crate::{error::{CIsizeResult, ResultExt, TryFromExt}, headers::{errno::Errno, sys_socket::SocketAddrExt}, util::PointerExt};
use crate::{
error::{CIsizeResult, ResultExt, TryFromExt},
headers::errno::Errno,
util::PointerExt,
};
use super::{msghdr, sockaddr, socklen_t};
use super::{msghdr, sockaddr, socklen_t, SocketAddrExt};
#[no_mangle]
unsafe extern "C" fn recv(fd: c_int, buffer: *mut c_void, len: usize, flags: c_int) -> CIsizeResult {
unsafe extern "C" fn recv(
fd: c_int,
buffer: *mut c_void,
len: usize,
flags: c_int,
) -> CIsizeResult {
recvfrom(fd, buffer, len, flags, null_mut(), null_mut())
}
@ -21,12 +38,24 @@ unsafe extern "C" fn recvfrom(
remote_len: *mut socklen_t,
) -> CIsizeResult {
let _ = flags;
let buffer = buffer.cast::<u8>().ensure_slice_mut(len);
let fd = RawFd::e_try_from(fd)?;
let mut peer = MaybeUninit::uninit();
let len = syscall::receive_from(fd, buffer, &mut peer).e_map_err(Errno::from)?;
if !remote.is_null() && !remote_len.is_null() {
let peer = peer.assume_init();
let payload = buffer.cast::<u8>().ensure_slice_mut(len);
let mut source = if remote.is_null() || remote_len.is_null() {
None
} else {
Some([0u8; 32])
};
let mut message = MessageHeaderMut {
payload,
source: source.as_mut().map(|x| &mut x[..]),
ancillary: None,
ancillary_len: 0,
};
let len = syscall::receive_message(fd, &mut message).e_map_err(Errno::from)?;
if let Some(source) = source.as_ref() {
let peer: SocketAddr = wire::from_slice(source)
.map_err(yggdrasil_rt::Error::from)
.e_map_err(Errno::from)?;
*remote_len = peer.to_c(remote, *remote_len)?;
}
CIsizeResult::success(len)
@ -41,7 +70,12 @@ unsafe extern "C" fn recvmsg(fd: c_int, message: *mut msghdr, flags: c_int) -> C
}
#[no_mangle]
unsafe extern "C" fn send(fd: c_int, data: *const c_void, len: usize, flags: c_int) -> CIsizeResult {
unsafe extern "C" fn send(
fd: c_int,
data: *const c_void,
len: usize,
flags: c_int,
) -> CIsizeResult {
sendto(fd, data, len, flags, null(), 0)
}
@ -64,12 +98,22 @@ unsafe extern "C" fn sendto(
) -> CIsizeResult {
let _ = flags;
let fd = RawFd::e_try_from(fd)?;
let data = data.cast::<u8>().ensure_slice(len);
let peer = if !remote.is_null() && remote_len != 0 {
Some(remote.to_rust(remote_len)?)
let payload = data.cast::<u8>().ensure_slice(len);
let destination = if remote.is_null() || remote_len == 0 {
let mut sockaddr_buf = [0; 32];
let sockaddr = remote.to_rust(len)?;
wire::to_slice(&sockaddr, &mut sockaddr_buf)
.map_err(yggdrasil_rt::Error::from)
.e_map_err(Errno::from)?;
Some(sockaddr_buf)
} else {
None
};
let len = syscall::send_to(fd, data, &peer).e_map_err(Errno::from)?;
let message = MessageHeader {
destination: destination.as_ref().map(|x| &x[..]),
payload,
ancillary: &[],
};
let len = syscall::send_message(fd, &message).e_map_err(Errno::from)?;
CIsizeResult::success(len)
}

View File

@ -115,7 +115,7 @@ impl SocketAddrExt<sockaddr> for SocketAddr {
match self {
Self::V4(v4) if len >= size_of::<sockaddr_in>() => v4.to_c(storage.cast(), len),
Self::V6(v6) if len >= size_of::<sockaddr_in6>() => v6.to_c(storage.cast(), len),
_ => EResult::Err(Errno::EINVAL)
_ => EResult::Err(Errno::EINVAL),
}
}
}

View File

@ -1,160 +1,151 @@
use core::ffi::{c_int, c_void};
use yggdrasil_rt::{
io::RawFd,
net::{self as rt, options},
};
use crate::{
error::{self, CIntZeroResult, CResult, OptionExt, ResultExt, TryFromExt},
headers::{
errno::Errno,
netinet_in::{IPPROTO_TCP, TCP_NODELAY},
sys_socket::{SocketAddrExt, SOL_SOCKET, SO_BROADCAST, SO_RCVTIMEO, SO_SNDTIMEO},
sys_time::timeval,
},
};
use crate::error::CIntZeroResult;
use super::{sockaddr, socklen_t};
#[no_mangle]
unsafe extern "C" fn getsockopt(
fd: c_int,
level: c_int,
name: c_int,
value: *mut c_void,
size: *mut socklen_t,
_fd: c_int,
_level: c_int,
_name: c_int,
_value: *mut c_void,
_size: *mut socklen_t,
) -> CIntZeroResult {
if value.is_null() || size.is_null() {
error::errno = Errno::EINVAL;
return CIntZeroResult::ERROR;
}
todo!()
// if value.is_null() || size.is_null() {
// error::errno = Errno::EINVAL;
// return CIntZeroResult::ERROR;
// }
let space = *size;
let fd = RawFd::e_try_from(fd)?;
// let space = *size;
// let fd = RawFd::e_try_from(fd)?;
*size = match (level, name) {
(SOL_SOCKET, SO_RCVTIMEO) if space >= size_of::<timeval>() => {
let timeout =
rt::get_socket_option!(fd, options::RecvTimeout).e_map_err(Errno::from)?;
let value = value.cast::<timeval>();
match timeout {
Some(timeout) => value.write(timeval::from(timeout)),
None => value.write(timeval::zero()),
}
size_of::<timeval>()
}
(SOL_SOCKET, SO_SNDTIMEO) => {
let timeout =
rt::get_socket_option!(fd, options::SendTimeout).e_map_err(Errno::from)?;
let value = value.cast::<timeval>();
match timeout {
Some(timeout) => value.write(timeval::from(timeout)),
None => value.write(timeval::zero()),
}
size_of::<timeval>()
}
(SOL_SOCKET, SO_BROADCAST) => {
let broadcast =
rt::get_socket_option!(fd, options::Broadcast).e_map_err(Errno::from)?;
let value = value.cast::<c_int>();
value.write(broadcast as c_int);
size_of::<c_int>()
}
(IPPROTO_TCP, TCP_NODELAY) => {
let broadcast = rt::get_socket_option!(fd, options::NoDelay).e_map_err(Errno::from)?;
let value = value.cast::<c_int>();
value.write(broadcast as c_int);
size_of::<c_int>()
}
_ => {
yggdrasil_rt::debug_trace!("Unhandled getsockopt({level}, {name}, {space})");
error::errno = Errno::EINVAL;
return CIntZeroResult::ERROR;
}
};
// *size = match (level, name) {
// (SOL_SOCKET, SO_RCVTIMEO) if space >= size_of::<timeval>() => {
// let timeout =
// rt::get_socket_option!(fd, options::RecvTimeout).e_map_err(Errno::from)?;
// let value = value.cast::<timeval>();
// match timeout {
// Some(timeout) => value.write(timeval::from(timeout)),
// None => value.write(timeval::zero()),
// }
// size_of::<timeval>()
// }
// (SOL_SOCKET, SO_SNDTIMEO) => {
// let timeout =
// rt::get_socket_option!(fd, options::SendTimeout).e_map_err(Errno::from)?;
// let value = value.cast::<timeval>();
// match timeout {
// Some(timeout) => value.write(timeval::from(timeout)),
// None => value.write(timeval::zero()),
// }
// size_of::<timeval>()
// }
// (SOL_SOCKET, SO_BROADCAST) => {
// let broadcast =
// rt::get_socket_option!(fd, options::Broadcast).e_map_err(Errno::from)?;
// let value = value.cast::<c_int>();
// value.write(broadcast as c_int);
// size_of::<c_int>()
// }
// (IPPROTO_TCP, TCP_NODELAY) => {
// let broadcast = rt::get_socket_option!(fd, options::NoDelay).e_map_err(Errno::from)?;
// let value = value.cast::<c_int>();
// value.write(broadcast as c_int);
// size_of::<c_int>()
// }
// _ => {
// yggdrasil_rt::debug_trace!("Unhandled getsockopt({level}, {name}, {space})");
// error::errno = Errno::EINVAL;
// return CIntZeroResult::ERROR;
// }
// };
CIntZeroResult::SUCCESS
// CIntZeroResult::SUCCESS
}
#[no_mangle]
unsafe extern "C" fn setsockopt(
fd: c_int,
level: c_int,
name: c_int,
value: *const c_void,
size: socklen_t,
_fd: c_int,
_level: c_int,
_name: c_int,
_value: *const c_void,
_size: socklen_t,
) -> CIntZeroResult {
if value.is_null() {
error::errno = Errno::EINVAL;
return CIntZeroResult::ERROR;
}
todo!()
// if value.is_null() {
// error::errno = Errno::EINVAL;
// return CIntZeroResult::ERROR;
// }
let fd = RawFd::e_try_from(fd)?;
// let fd = RawFd::e_try_from(fd)?;
match (level, name) {
(SOL_SOCKET, SO_RCVTIMEO) if size == size_of::<timeval>() => {
let timeval = *value.cast::<timeval>();
let timeout = timeval.to_duration_opt();
rt::set_socket_option::<options::RecvTimeout>(fd, &timeout).e_map_err(Errno::from)?;
}
(SOL_SOCKET, SO_SNDTIMEO) if size == size_of::<timeval>() => {
let timeval = *value.cast::<timeval>();
let timeout = timeval.to_duration_opt();
rt::set_socket_option::<options::SendTimeout>(fd, &timeout).e_map_err(Errno::from)?;
}
(SOL_SOCKET, SO_BROADCAST) if size == size_of::<c_int>() => {
let value = *value.cast::<c_int>() != 0;
rt::set_socket_option::<options::Broadcast>(fd, &value).e_map_err(Errno::from)?;
}
(IPPROTO_TCP, TCP_NODELAY) if size == size_of::<c_int>() => {
let value = *value.cast::<c_int>() != 0;
rt::set_socket_option::<options::NoDelay>(fd, &value).e_map_err(Errno::from)?;
}
_ => {
yggdrasil_rt::debug_trace!("Unhandled setsockopt({level}, {name}, {size})");
error::errno = Errno::EINVAL;
return CIntZeroResult::ERROR;
}
}
// match (level, name) {
// (SOL_SOCKET, SO_RCVTIMEO) if size == size_of::<timeval>() => {
// let timeval = *value.cast::<timeval>();
// let timeout = timeval.to_duration_opt();
// rt::set_socket_option::<options::RecvTimeout>(fd, &timeout).e_map_err(Errno::from)?;
// }
// (SOL_SOCKET, SO_SNDTIMEO) if size == size_of::<timeval>() => {
// let timeval = *value.cast::<timeval>();
// let timeout = timeval.to_duration_opt();
// rt::set_socket_option::<options::SendTimeout>(fd, &timeout).e_map_err(Errno::from)?;
// }
// (SOL_SOCKET, SO_BROADCAST) if size == size_of::<c_int>() => {
// let value = *value.cast::<c_int>() != 0;
// rt::set_socket_option::<options::Broadcast>(fd, &value).e_map_err(Errno::from)?;
// }
// (IPPROTO_TCP, TCP_NODELAY) if size == size_of::<c_int>() => {
// let value = *value.cast::<c_int>() != 0;
// rt::set_socket_option::<options::NoDelay>(fd, &value).e_map_err(Errno::from)?;
// }
// _ => {
// yggdrasil_rt::debug_trace!("Unhandled setsockopt({level}, {name}, {size})");
// error::errno = Errno::EINVAL;
// return CIntZeroResult::ERROR;
// }
// }
CIntZeroResult::SUCCESS
// CIntZeroResult::SUCCESS
}
#[no_mangle]
unsafe extern "C" fn getpeername(
fd: c_int,
remote: *mut sockaddr,
len: *mut socklen_t,
_fd: c_int,
_remote: *mut sockaddr,
_len: *mut socklen_t,
) -> CIntZeroResult {
if remote.is_null() || len.is_null() {
error::errno = Errno::EINVAL;
return CIntZeroResult::ERROR;
}
todo!()
// if remote.is_null() || len.is_null() {
// error::errno = Errno::EINVAL;
// return CIntZeroResult::ERROR;
// }
let fd = RawFd::e_try_from(fd)?;
let address = rt::get_socket_option!(fd, options::PeerAddress).e_map_err(Errno::from)?;
let address = address.e_ok_or(Errno::ENOTCONN)?;
// let fd = RawFd::e_try_from(fd)?;
// let address = rt::get_socket_option!(fd, options::PeerAddress).e_map_err(Errno::from)?;
// let address = address.e_ok_or(Errno::ENOTCONN)?;
*len = address.to_c(remote, *len)?;
CIntZeroResult::SUCCESS
// *len = address.to_c(remote, *len)?;
// CIntZeroResult::SUCCESS
}
#[no_mangle]
unsafe extern "C" fn getsockname(
fd: c_int,
local: *mut sockaddr,
len: *mut socklen_t,
_fd: c_int,
_local: *mut sockaddr,
_len: *mut socklen_t,
) -> CIntZeroResult {
if local.is_null() || len.is_null() {
error::errno = Errno::EINVAL;
return CIntZeroResult::ERROR;
}
todo!()
// if local.is_null() || len.is_null() {
// error::errno = Errno::EINVAL;
// return CIntZeroResult::ERROR;
// }
let fd = RawFd::e_try_from(fd)?;
let address = rt::get_socket_option!(fd, options::LocalAddress).e_map_err(Errno::from)?;
let address = address.e_ok_or(Errno::ENOTCONN)?;
// let fd = RawFd::e_try_from(fd)?;
// let address = rt::get_socket_option!(fd, options::LocalAddress).e_map_err(Errno::from)?;
// let address = address.e_ok_or(Errno::ENOTCONN)?;
*len = address.to_c(local, *len)?;
CIntZeroResult::SUCCESS
// *len = address.to_c(local, *len)?;
// CIntZeroResult::SUCCESS
}

View File

@ -1,44 +1,59 @@
use core::{ffi::c_int, mem::MaybeUninit};
use core::{ffi::c_int, net::SocketAddr};
use yggdrasil_abi::abi_serde::wire;
use yggdrasil_rt::{io::RawFd, net as rt, sys as syscall};
use crate::{
error::{self, CFdResult, CIntCountResult, CIntZeroResult, CResult, ResultExt, TryFromExt},
headers::{
errno::Errno,
sys_socket::{AF_INET, SHUT_RD, SHUT_RDWR, SHUT_WR, SOCK_DGRAM, SOCK_STREAM},
sys_socket::{
SocketAddrExt, AF_INET, SHUT_RD, SHUT_RDWR, SHUT_WR, SOCK_DGRAM, SOCK_STREAM,
},
},
};
use super::{sockaddr, socklen_t, SocketAddrExt};
use super::{sockaddr, socklen_t};
#[no_mangle]
unsafe extern "C" fn accept(fd: c_int, remote: *mut sockaddr, len: *mut socklen_t) -> CFdResult {
let listener_fd = RawFd::e_try_from(fd)?;
let mut address = MaybeUninit::uninit();
let stream_fd = syscall::accept(listener_fd, &mut address).e_map_err(Errno::from)?;
if !remote.is_null() && !len.is_null() {
let address = address.assume_init();
*len = address.to_c(remote, *len)?;
}
let stream_fd = if remote.is_null() || len.is_null() {
syscall::accept(listener_fd, None).e_map_err(Errno::from)?
} else {
let mut sockaddr_buf = [0; 32];
let stream_fd =
syscall::accept(listener_fd, Some(&mut sockaddr_buf)).e_map_err(Errno::from)?;
let sockaddr: SocketAddr = wire::from_slice(&sockaddr_buf)
.map_err(yggdrasil_rt::Error::from)
.e_map_err(Errno::from)?;
*len = sockaddr.to_c(remote, *len)?;
stream_fd
};
CFdResult::success(stream_fd)
}
#[no_mangle]
unsafe extern "C" fn bind(fd: c_int, local: *const sockaddr, len: socklen_t) -> CIntZeroResult {
let mut sockaddr_buf = [0; 32];
let fd = RawFd::e_try_from(fd)?;
let local = local.to_rust(len)?;
syscall::bind(fd, &local).e_map_err(Errno::from)?;
let sockaddr_len = wire::to_slice(&local, &mut sockaddr_buf)
.map_err(yggdrasil_rt::Error::from)
.e_map_err(Errno::from)?;
syscall::bind(fd, &sockaddr_buf[..sockaddr_len]).e_map_err(Errno::from)?;
CIntZeroResult::SUCCESS
}
#[no_mangle]
unsafe extern "C" fn connect(fd: c_int, remote: *const sockaddr, len: socklen_t) -> CIntZeroResult {
let fd = RawFd::e_try_from(fd)?;
let mut sockaddr_buf = [0; 256];
let remote = remote.to_rust(len)?;
syscall::connect(fd, &remote).e_map_err(Errno::from)?;
let sockaddr_len = wire::to_slice(&remote, &mut sockaddr_buf)
.map_err(yggdrasil_rt::Error::from)
.e_map_err(Errno::from)?;
syscall::connect(fd, &sockaddr_buf[..sockaddr_len]).e_map_err(Errno::from)?;
CIntZeroResult::SUCCESS
}