libc: implement socket functionality
This commit is contained in:
parent
a4e441d236
commit
dcf3658bd1
71
test.c
71
test.c
@ -1,14 +1,85 @@
|
||||
#include <netinet/in.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static void fmt_inaddr(char *buffer, const struct sockaddr_in *inaddr) {
|
||||
uint8_t a = (uint8_t) inaddr->sin_addr.s_addr;
|
||||
uint8_t b = (uint8_t) (inaddr->sin_addr.s_addr >> 8);
|
||||
uint8_t c = (uint8_t) (inaddr->sin_addr.s_addr >> 16);
|
||||
uint8_t d = (uint8_t) (inaddr->sin_addr.s_addr >> 24);
|
||||
uint16_t port = ntohs(inaddr->sin_port);
|
||||
sprintf(buffer, "%hhu.%hhu.%hhu.%hhu:%hu", a, b, c, d, port);
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv) {
|
||||
int fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
if (fd < 0) {
|
||||
perror("socket()");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
struct sockaddr_in sa;
|
||||
socklen_t slen;
|
||||
char buffer[256];
|
||||
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sin_family = AF_INET;
|
||||
sa.sin_port = htons(4321);
|
||||
sa.sin_addr.s_addr = INADDR_ANY;
|
||||
|
||||
if (bind(fd, (const struct sockaddr *) &sa, sizeof(sa)) != 0) {
|
||||
perror("bind()");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (listen(fd, 64) != 0) {
|
||||
perror("listen()");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
int rfd;
|
||||
|
||||
slen = sizeof(sa);
|
||||
if ((rfd = accept(fd, (struct sockaddr *) &sa, &slen)) < 0) {
|
||||
perror("accept()");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
fmt_inaddr(buffer, &sa);
|
||||
printf("Received connection from %s\n", buffer);
|
||||
|
||||
while (1) {
|
||||
ssize_t len;
|
||||
|
||||
if ((len = recv(rfd, buffer, sizeof(buffer), 0)) < 0) {
|
||||
perror("recv()");
|
||||
break;
|
||||
}
|
||||
|
||||
if (len == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (len >= 4 && !strncmp(buffer, "quit", 4)) {
|
||||
break;
|
||||
}
|
||||
|
||||
fwrite(buffer, 1, len, stdout);
|
||||
|
||||
if ((len = send(rfd, buffer, len, 0)) < 0) {
|
||||
perror("send()");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
printf("Connection closed\n");
|
||||
close(rfd);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,6 +1,12 @@
|
||||
use core::ffi::c_int;
|
||||
use core::{ffi::c_int, net::{Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6}};
|
||||
|
||||
use super::sys_socket::sa_family_t;
|
||||
use crate::{
|
||||
error::EResult,
|
||||
headers::sys_socket::{AF_INET, AF_INET6},
|
||||
util::PointerExt,
|
||||
};
|
||||
|
||||
use super::sys_socket::{sa_family_t, socklen_t, SocketAddrExt};
|
||||
|
||||
pub type in_port_t = u16;
|
||||
pub type in_addr_t = u32;
|
||||
@ -8,13 +14,13 @@ pub type in_addr_t = u32;
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[repr(C)]
|
||||
pub struct in_addr {
|
||||
pub s_addr: in_addr_t
|
||||
pub s_addr: in_addr_t,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[repr(C)]
|
||||
pub struct in6_addr {
|
||||
pub s6_addr: [u8; 16]
|
||||
pub s6_addr: [u8; 16],
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
@ -32,7 +38,7 @@ pub struct sockaddr_in6 {
|
||||
pub sin6_port: in_port_t,
|
||||
pub sin6_flowinfo: u32,
|
||||
pub sin6_addr: in6_addr,
|
||||
pub sin6_scope_id: u32
|
||||
pub sin6_scope_id: u32,
|
||||
}
|
||||
|
||||
// TODO more IPv6
|
||||
@ -58,3 +64,65 @@ pub const IPV6_MULTICAST_IF: c_int = 6004;
|
||||
pub const IPV6_MULTICAST_LOOP: c_int = 6005;
|
||||
pub const IPV6_UNICAST_HOPS: c_int = 6006;
|
||||
pub const IPV6_V6ONLY: c_int = 6007;
|
||||
|
||||
impl in_addr {
|
||||
pub fn to_rust(&self) -> Ipv4Addr {
|
||||
Ipv4Addr::from(self.s_addr)
|
||||
}
|
||||
}
|
||||
|
||||
impl in6_addr {
|
||||
pub fn to_rust(&self) -> Ipv6Addr {
|
||||
Ipv6Addr::from(self.s6_addr)
|
||||
}
|
||||
}
|
||||
|
||||
impl sockaddr_in {
|
||||
pub unsafe fn to_rust(self: *const Self) -> EResult<SocketAddrV4> {
|
||||
let this = self.ensure();
|
||||
debug_assert_eq!(this.sin_family, AF_INET as u16);
|
||||
let ip = this.sin_addr.to_rust();
|
||||
let port = u16::from_be(this.sin_port);
|
||||
EResult::Ok(SocketAddrV4::new(ip, port))
|
||||
}
|
||||
}
|
||||
|
||||
impl sockaddr_in6 {
|
||||
pub unsafe fn to_rust(self: *const Self) -> EResult<SocketAddrV6> {
|
||||
let this = self.ensure();
|
||||
debug_assert_eq!(this.sin6_family, AF_INET6 as u16);
|
||||
let ip = this.sin6_addr.to_rust();
|
||||
let port = u16::from_be(this.sin6_port);
|
||||
let flowinfo = u32::from_be(this.sin6_flowinfo);
|
||||
let scope_id = u32::from_be(this.sin6_scope_id);
|
||||
EResult::Ok(SocketAddrV6::new(ip, port, flowinfo, scope_id))
|
||||
}
|
||||
}
|
||||
|
||||
impl SocketAddrExt<sockaddr_in> for SocketAddrV4 {
|
||||
fn to_c(
|
||||
&self,
|
||||
storage: *mut sockaddr_in,
|
||||
len: socklen_t,
|
||||
) -> EResult<socklen_t> {
|
||||
let storage = unsafe { storage.ensure_mut() };
|
||||
debug_assert!(len >= size_of::<sockaddr_in>());
|
||||
storage.sin_family = AF_INET as u16;
|
||||
storage.sin_port = self.port().to_be();
|
||||
storage.sin_addr.s_addr = self.ip().to_bits().to_be();
|
||||
EResult::Ok(size_of::<sockaddr_in>())
|
||||
}
|
||||
}
|
||||
|
||||
impl SocketAddrExt<sockaddr_in6> for SocketAddrV6 {
|
||||
fn to_c(&self, storage: *mut sockaddr_in6, len: socklen_t) -> EResult<socklen_t> {
|
||||
let storage = unsafe { storage.ensure_mut() };
|
||||
debug_assert!(len >= size_of::<sockaddr_in6>());
|
||||
storage.sin6_family = AF_INET6 as u16;
|
||||
storage.sin6_port = self.port().to_be();
|
||||
storage.sin6_addr.s6_addr = self.ip().octets();
|
||||
storage.sin6_flowinfo = self.flowinfo().to_be();
|
||||
storage.sin6_scope_id = self.scope_id().to_be();
|
||||
EResult::Ok(size_of::<sockaddr_in6>())
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,14 @@
|
||||
use core::ffi::{c_int, c_void};
|
||||
use core::{ffi::{c_int, c_void}, mem::MaybeUninit, ptr::{null, null_mut}};
|
||||
|
||||
use yggdrasil_rt::{io::RawFd, sys as syscall};
|
||||
|
||||
use crate::{error::{CIsizeResult, ResultExt, TryFromExt}, headers::{errno::Errno, sys_socket::SocketAddrExt}, util::PointerExt};
|
||||
|
||||
use super::{msghdr, sockaddr, socklen_t};
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn recv(fd: c_int, buffer: *mut c_void, len: usize, flags: c_int) -> isize {
|
||||
let _ = fd;
|
||||
let _ = buffer;
|
||||
let _ = len;
|
||||
let _ = flags;
|
||||
todo!()
|
||||
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())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@ -19,18 +19,21 @@ unsafe extern "C" fn recvfrom(
|
||||
flags: c_int,
|
||||
remote: *mut sockaddr,
|
||||
remote_len: *mut socklen_t,
|
||||
) -> isize {
|
||||
let _ = fd;
|
||||
let _ = buffer;
|
||||
let _ = len;
|
||||
) -> CIsizeResult {
|
||||
let _ = flags;
|
||||
let _ = remote;
|
||||
let _ = remote_len;
|
||||
todo!()
|
||||
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();
|
||||
*remote_len = peer.to_c(remote, *remote_len)?;
|
||||
}
|
||||
CIsizeResult::success(len)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn recvmsg(fd: c_int, message: *mut msghdr, flags: c_int) -> isize {
|
||||
unsafe extern "C" fn recvmsg(fd: c_int, message: *mut msghdr, flags: c_int) -> CIsizeResult {
|
||||
let _ = fd;
|
||||
let _ = message;
|
||||
let _ = flags;
|
||||
@ -38,15 +41,12 @@ unsafe extern "C" fn recvmsg(fd: c_int, message: *mut msghdr, flags: c_int) -> i
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn send(fd: c_int, data: *const c_void, len: usize) -> isize {
|
||||
let _ = fd;
|
||||
let _ = data;
|
||||
let _ = len;
|
||||
todo!()
|
||||
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)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn sendmsg(fd: c_int, message: *const msghdr, flags: c_int) -> isize {
|
||||
unsafe extern "C" fn sendmsg(fd: c_int, message: *const msghdr, flags: c_int) -> CIsizeResult {
|
||||
let _ = fd;
|
||||
let _ = message;
|
||||
let _ = flags;
|
||||
@ -61,12 +61,15 @@ unsafe extern "C" fn sendto(
|
||||
flags: c_int,
|
||||
remote: *const sockaddr,
|
||||
remote_len: socklen_t,
|
||||
) -> isize {
|
||||
let _ = fd;
|
||||
let _ = data;
|
||||
let _ = len;
|
||||
) -> CIsizeResult {
|
||||
let _ = flags;
|
||||
let _ = remote;
|
||||
let _ = remote_len;
|
||||
todo!()
|
||||
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)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let len = syscall::send_to(fd, data, &peer).e_map_err(Errno::from)?;
|
||||
CIsizeResult::success(len)
|
||||
}
|
||||
|
@ -1,4 +1,8 @@
|
||||
use core::ffi::{c_int, c_void};
|
||||
use core::{ffi::{c_int, c_void}, net::SocketAddr};
|
||||
|
||||
use crate::{error::EResult, headers::errno::Errno, util::PointerExt};
|
||||
|
||||
use super::netinet_in::{sockaddr_in, sockaddr_in6};
|
||||
|
||||
mod io;
|
||||
mod option;
|
||||
@ -28,7 +32,7 @@ pub struct sockaddr {
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[repr(C)]
|
||||
pub struct iovec {
|
||||
__dummy: u32
|
||||
__dummy: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
@ -40,7 +44,7 @@ pub struct msghdr {
|
||||
pub msg_iovlen: c_int,
|
||||
pub msg_control: *mut c_void,
|
||||
pub msg_controllen: socklen_t,
|
||||
pub msg_flags: c_int
|
||||
pub msg_flags: c_int,
|
||||
}
|
||||
|
||||
// TODO struct cmsghdr
|
||||
@ -84,3 +88,31 @@ pub const SHUT_RD: c_int = 1 << 0;
|
||||
pub const SHUT_WR: c_int = 1 << 1;
|
||||
pub const SHUT_RDWR: c_int = SHUT_RD | SHUT_WR;
|
||||
|
||||
pub(crate) trait SocketAddrExt<T> {
|
||||
fn to_c(&self, storage: *mut T, len: socklen_t) -> EResult<socklen_t>;
|
||||
}
|
||||
|
||||
impl sockaddr {
|
||||
pub unsafe fn to_rust(self: *const Self, len: socklen_t) -> EResult<SocketAddr> {
|
||||
let family = self.ensure().sa_family as c_int;
|
||||
match family {
|
||||
AF_INET if len == size_of::<sockaddr_in>() => {
|
||||
self.cast::<sockaddr_in>().to_rust().map(SocketAddr::V4)
|
||||
}
|
||||
AF_INET6 if len == size_of::<sockaddr_in6>() => {
|
||||
self.cast::<sockaddr_in6>().to_rust().map(SocketAddr::V6)
|
||||
}
|
||||
_ => EResult::Err(Errno::ENOTSUPP),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SocketAddrExt<sockaddr> for SocketAddr {
|
||||
fn to_c(&self, storage: *mut sockaddr, len: socklen_t) -> EResult<socklen_t> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,21 @@
|
||||
use core::ffi::{c_int, c_void};
|
||||
|
||||
use super::socklen_t;
|
||||
use yggdrasil_rt::{
|
||||
io::RawFd,
|
||||
net::{self as rt, SocketOption},
|
||||
sys as syscall,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
error::{self, CIntZeroResult, CResult, OptionExt, ResultExt, TryFromExt},
|
||||
headers::{
|
||||
errno::Errno,
|
||||
sys_socket::{SocketAddrExt, SOL_SOCKET, SO_BROADCAST, SO_RCVTIMEO, SO_SNDTIMEO},
|
||||
sys_time::timeval,
|
||||
},
|
||||
};
|
||||
|
||||
use super::{sockaddr, socklen_t};
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn getsockopt(
|
||||
@ -9,13 +24,50 @@ unsafe extern "C" fn getsockopt(
|
||||
name: c_int,
|
||||
value: *mut c_void,
|
||||
size: *mut socklen_t,
|
||||
) -> c_int {
|
||||
let _ = fd;
|
||||
let _ = level;
|
||||
let _ = name;
|
||||
let _ = value;
|
||||
let _ = size;
|
||||
todo!()
|
||||
) -> CIntZeroResult {
|
||||
if value.is_null() || size.is_null() {
|
||||
error::errno = Errno::EINVAL;
|
||||
return CIntZeroResult::ERROR;
|
||||
}
|
||||
|
||||
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_option1!(fd, RecvTimeout: Option).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_option1!(fd, SendTimeout: Option).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_option1!(fd, Broadcast: bool).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
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@ -25,11 +77,76 @@ unsafe extern "C" fn setsockopt(
|
||||
name: c_int,
|
||||
value: *const c_void,
|
||||
size: socklen_t,
|
||||
) -> c_int {
|
||||
let _ = fd;
|
||||
let _ = level;
|
||||
let _ = name;
|
||||
let _ = value;
|
||||
let _ = size;
|
||||
todo!()
|
||||
) -> CIntZeroResult {
|
||||
if value.is_null() {
|
||||
error::errno = Errno::EINVAL;
|
||||
return CIntZeroResult::ERROR;
|
||||
}
|
||||
|
||||
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();
|
||||
syscall::set_socket_option(fd, &SocketOption::RecvTimeout(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();
|
||||
syscall::set_socket_option(fd, &SocketOption::SendTimeout(timeout))
|
||||
.e_map_err(Errno::from)?;
|
||||
}
|
||||
(SOL_SOCKET, SO_BROADCAST) if size == size_of::<c_int>() => {
|
||||
let value = *value.cast::<c_int>() != 0;
|
||||
syscall::set_socket_option(fd, &SocketOption::Broadcast(value))
|
||||
.e_map_err(Errno::from)?;
|
||||
}
|
||||
_ => {
|
||||
yggdrasil_rt::debug_trace!("Unhandled setsockopt({level}, {name}, {size})");
|
||||
error::errno = Errno::EINVAL;
|
||||
return CIntZeroResult::ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
CIntZeroResult::SUCCESS
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn getpeername(
|
||||
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;
|
||||
}
|
||||
|
||||
let fd = RawFd::e_try_from(fd)?;
|
||||
let address = rt::get_socket_option1!(fd, PeerAddress: Option).e_map_err(Errno::from)?;
|
||||
let address = address.e_ok_or(Errno::ENOTCONN)?;
|
||||
|
||||
*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,
|
||||
) -> CIntZeroResult {
|
||||
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_option1!(fd, LocalAddress: Option).e_map_err(Errno::from)?;
|
||||
let address = address.e_ok_or(Errno::ENOTCONN)?;
|
||||
|
||||
*len = address.to_c(local, *len)?;
|
||||
CIntZeroResult::SUCCESS
|
||||
}
|
||||
|
@ -1,87 +1,94 @@
|
||||
use core::ffi::c_int;
|
||||
use core::{ffi::c_int, mem::MaybeUninit};
|
||||
|
||||
use yggdrasil_rt::{io::RawFd, net as rt, sys as syscall};
|
||||
|
||||
use crate::{
|
||||
error::{self, CFdResult, CResult},
|
||||
error::{self, CFdResult, CIntCountResult, CIntZeroResult, CResult, ResultExt, TryFromExt},
|
||||
headers::{
|
||||
errno::Errno,
|
||||
sys_socket::{AF_INET, SOCK_DGRAM, SOCK_STREAM},
|
||||
sys_socket::{AF_INET, SHUT_RD, SHUT_RDWR, SHUT_WR, SOCK_DGRAM, SOCK_STREAM},
|
||||
},
|
||||
};
|
||||
|
||||
use super::{sockaddr, socklen_t};
|
||||
use super::{sockaddr, socklen_t, SocketAddrExt};
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn accept(fd: c_int, remote: *mut sockaddr, len: *mut socklen_t) -> c_int {
|
||||
let _ = fd;
|
||||
let _ = remote;
|
||||
let _ = len;
|
||||
todo!()
|
||||
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)?;
|
||||
}
|
||||
|
||||
CFdResult::success(stream_fd)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn bind(fd: c_int, local: *const sockaddr, len: socklen_t) -> c_int {
|
||||
let _ = fd;
|
||||
let _ = local;
|
||||
let _ = len;
|
||||
|
||||
todo!()
|
||||
unsafe extern "C" fn bind(fd: c_int, local: *const sockaddr, len: socklen_t) -> CIntZeroResult {
|
||||
let fd = RawFd::e_try_from(fd)?;
|
||||
let local = local.to_rust(len)?;
|
||||
syscall::bind(fd, &local).e_map_err(Errno::from)?;
|
||||
CIntZeroResult::SUCCESS
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn connect(fd: c_int, remote: *const sockaddr, len: socklen_t) -> c_int {
|
||||
let _ = fd;
|
||||
let _ = remote;
|
||||
let _ = len;
|
||||
todo!()
|
||||
unsafe extern "C" fn connect(fd: c_int, remote: *const sockaddr, len: socklen_t) -> CIntZeroResult {
|
||||
let fd = RawFd::e_try_from(fd)?;
|
||||
let remote = remote.to_rust(len)?;
|
||||
syscall::connect(fd, &remote).e_map_err(Errno::from)?;
|
||||
CIntZeroResult::SUCCESS
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn getpeername(fd: c_int, remote: *mut sockaddr, len: *mut socklen_t) -> c_int {
|
||||
let _ = fd;
|
||||
let _ = remote;
|
||||
let _ = len;
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn getsockname(fd: c_int, local: *mut sockaddr, len: *mut socklen_t) -> c_int {
|
||||
let _ = fd;
|
||||
let _ = local;
|
||||
let _ = len;
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn listen(fd: c_int, backlog: c_int) -> c_int {
|
||||
let _ = fd;
|
||||
unsafe extern "C" fn listen(fd: c_int, backlog: c_int) -> CIntZeroResult {
|
||||
let _ = backlog;
|
||||
todo!()
|
||||
let fd = RawFd::e_try_from(fd)?;
|
||||
syscall::listen(fd).e_map_err(Errno::from)?;
|
||||
CIntZeroResult::SUCCESS
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn shutdown(fd: c_int, how: c_int) -> c_int {
|
||||
let _ = fd;
|
||||
let _ = how;
|
||||
todo!()
|
||||
unsafe extern "C" fn shutdown(fd: c_int, how: c_int) -> CIntZeroResult {
|
||||
let fd = RawFd::e_try_from(fd)?;
|
||||
let how = match how {
|
||||
SHUT_RD => rt::SocketShutdown::READ,
|
||||
SHUT_WR => rt::SocketShutdown::WRITE,
|
||||
SHUT_RDWR => rt::SocketShutdown::READ | rt::SocketShutdown::WRITE,
|
||||
_ => {
|
||||
error::errno = Errno::EINVAL;
|
||||
return CIntZeroResult::ERROR;
|
||||
}
|
||||
};
|
||||
|
||||
syscall::shutdown(fd, how).e_map_err(Errno::from)?;
|
||||
|
||||
CIntZeroResult::SUCCESS
|
||||
}
|
||||
|
||||
// TODO out-of-band data in sockets
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn sockatmark(fd: c_int) -> c_int {
|
||||
let _ = fd;
|
||||
todo!()
|
||||
unsafe extern "C" fn sockatmark(_fd: c_int) -> CIntCountResult {
|
||||
error::errno = Errno::EINVAL;
|
||||
CIntCountResult::ERROR
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn socket(domain: c_int, ty: c_int, proto: c_int) -> CFdResult {
|
||||
match (domain, ty, proto) {
|
||||
(AF_INET, SOCK_STREAM, 0) => todo!(),
|
||||
(AF_INET, SOCK_DGRAM, 0) => todo!(),
|
||||
let ty = match (domain, ty, proto) {
|
||||
(AF_INET, SOCK_STREAM, 0) => rt::SocketType::TcpStream,
|
||||
(AF_INET, SOCK_DGRAM, 0) => rt::SocketType::UdpPacket,
|
||||
(_, _, _) => {
|
||||
yggdrasil_rt::debug_trace!("Unsupported socket({domain}, {ty}, {proto})");
|
||||
error::errno = Errno::ENOTSUPP;
|
||||
CFdResult::ERROR
|
||||
return CFdResult::ERROR;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let fd = syscall::create_socket(ty).e_map_err(Errno::from)?;
|
||||
CFdResult::success(fd)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
@ -1,5 +1,7 @@
|
||||
use core::{ffi::{c_char, c_int, c_long, c_void}, time::Duration};
|
||||
|
||||
use yggdrasil_abi::time::MICROSECONDS_IN_SECOND;
|
||||
|
||||
use super::sys_types::{suseconds_t, time_t};
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
|
||||
@ -59,6 +61,25 @@ impl timespec {
|
||||
}
|
||||
}
|
||||
|
||||
impl timeval {
|
||||
pub const fn zero() -> Self {
|
||||
Self {
|
||||
tv_sec: time_t(0),
|
||||
tv_usec: 0
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_duration_opt(&self) -> Option<Duration> {
|
||||
if self.tv_sec.0 == 0 && self.tv_usec == 0 {
|
||||
None
|
||||
} else {
|
||||
let seconds = (self.tv_sec.0 as u64).saturating_add(self.tv_usec / MICROSECONDS_IN_SECOND);
|
||||
let nanoseconds = (self.tv_usec % MICROSECONDS_IN_SECOND) * 1000;
|
||||
Some(Duration::new(seconds, nanoseconds as u32))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<__ygg_timespec_t> for Duration {
|
||||
fn from(value: __ygg_timespec_t) -> Self {
|
||||
Self::new(
|
||||
@ -76,3 +97,12 @@ impl From<Duration> for __ygg_timespec_t {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Duration> for timeval {
|
||||
fn from(value: Duration) -> Self {
|
||||
Self {
|
||||
tv_sec: time_t(value.as_secs().try_into().unwrap()),
|
||||
tv_usec: value.subsec_micros() as _
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user