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 <netinet/in.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdio.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 main(int argc, const char **argv) {
|
||||||
int fd = socket(AF_INET, SOCK_STREAM, 0);
|
int fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
perror("socket()");
|
perror("socket()");
|
||||||
return EXIT_FAILURE;
|
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;
|
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_port_t = u16;
|
||||||
pub type in_addr_t = u32;
|
pub type in_addr_t = u32;
|
||||||
@ -8,13 +14,13 @@ pub type in_addr_t = u32;
|
|||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct in_addr {
|
pub struct in_addr {
|
||||||
pub s_addr: in_addr_t
|
pub s_addr: in_addr_t,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct in6_addr {
|
pub struct in6_addr {
|
||||||
pub s6_addr: [u8; 16]
|
pub s6_addr: [u8; 16],
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
@ -32,7 +38,7 @@ pub struct sockaddr_in6 {
|
|||||||
pub sin6_port: in_port_t,
|
pub sin6_port: in_port_t,
|
||||||
pub sin6_flowinfo: u32,
|
pub sin6_flowinfo: u32,
|
||||||
pub sin6_addr: in6_addr,
|
pub sin6_addr: in6_addr,
|
||||||
pub sin6_scope_id: u32
|
pub sin6_scope_id: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO more IPv6
|
// 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_MULTICAST_LOOP: c_int = 6005;
|
||||||
pub const IPV6_UNICAST_HOPS: c_int = 6006;
|
pub const IPV6_UNICAST_HOPS: c_int = 6006;
|
||||||
pub const IPV6_V6ONLY: c_int = 6007;
|
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};
|
use super::{msghdr, sockaddr, socklen_t};
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
unsafe extern "C" fn recv(fd: c_int, buffer: *mut c_void, len: usize, flags: c_int) -> isize {
|
unsafe extern "C" fn recv(fd: c_int, buffer: *mut c_void, len: usize, flags: c_int) -> CIsizeResult {
|
||||||
let _ = fd;
|
recvfrom(fd, buffer, len, flags, null_mut(), null_mut())
|
||||||
let _ = buffer;
|
|
||||||
let _ = len;
|
|
||||||
let _ = flags;
|
|
||||||
todo!()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
@ -19,18 +19,21 @@ unsafe extern "C" fn recvfrom(
|
|||||||
flags: c_int,
|
flags: c_int,
|
||||||
remote: *mut sockaddr,
|
remote: *mut sockaddr,
|
||||||
remote_len: *mut socklen_t,
|
remote_len: *mut socklen_t,
|
||||||
) -> isize {
|
) -> CIsizeResult {
|
||||||
let _ = fd;
|
|
||||||
let _ = buffer;
|
|
||||||
let _ = len;
|
|
||||||
let _ = flags;
|
let _ = flags;
|
||||||
let _ = remote;
|
let buffer = buffer.cast::<u8>().ensure_slice_mut(len);
|
||||||
let _ = remote_len;
|
let fd = RawFd::e_try_from(fd)?;
|
||||||
todo!()
|
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]
|
#[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 _ = fd;
|
||||||
let _ = message;
|
let _ = message;
|
||||||
let _ = flags;
|
let _ = flags;
|
||||||
@ -38,15 +41,12 @@ unsafe extern "C" fn recvmsg(fd: c_int, message: *mut msghdr, flags: c_int) -> i
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
unsafe extern "C" fn send(fd: c_int, data: *const c_void, len: usize) -> isize {
|
unsafe extern "C" fn send(fd: c_int, data: *const c_void, len: usize, flags: c_int) -> CIsizeResult {
|
||||||
let _ = fd;
|
sendto(fd, data, len, flags, null(), 0)
|
||||||
let _ = data;
|
|
||||||
let _ = len;
|
|
||||||
todo!()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[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 _ = fd;
|
||||||
let _ = message;
|
let _ = message;
|
||||||
let _ = flags;
|
let _ = flags;
|
||||||
@ -61,12 +61,15 @@ unsafe extern "C" fn sendto(
|
|||||||
flags: c_int,
|
flags: c_int,
|
||||||
remote: *const sockaddr,
|
remote: *const sockaddr,
|
||||||
remote_len: socklen_t,
|
remote_len: socklen_t,
|
||||||
) -> isize {
|
) -> CIsizeResult {
|
||||||
let _ = fd;
|
|
||||||
let _ = data;
|
|
||||||
let _ = len;
|
|
||||||
let _ = flags;
|
let _ = flags;
|
||||||
let _ = remote;
|
let fd = RawFd::e_try_from(fd)?;
|
||||||
let _ = remote_len;
|
let data = data.cast::<u8>().ensure_slice(len);
|
||||||
todo!()
|
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 io;
|
||||||
mod option;
|
mod option;
|
||||||
@ -28,7 +32,7 @@ pub struct sockaddr {
|
|||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct iovec {
|
pub struct iovec {
|
||||||
__dummy: u32
|
__dummy: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
@ -40,7 +44,7 @@ pub struct msghdr {
|
|||||||
pub msg_iovlen: c_int,
|
pub msg_iovlen: c_int,
|
||||||
pub msg_control: *mut c_void,
|
pub msg_control: *mut c_void,
|
||||||
pub msg_controllen: socklen_t,
|
pub msg_controllen: socklen_t,
|
||||||
pub msg_flags: c_int
|
pub msg_flags: c_int,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO struct cmsghdr
|
// 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_WR: c_int = 1 << 1;
|
||||||
pub const SHUT_RDWR: c_int = SHUT_RD | SHUT_WR;
|
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 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]
|
#[no_mangle]
|
||||||
unsafe extern "C" fn getsockopt(
|
unsafe extern "C" fn getsockopt(
|
||||||
@ -9,13 +24,50 @@ unsafe extern "C" fn getsockopt(
|
|||||||
name: c_int,
|
name: c_int,
|
||||||
value: *mut c_void,
|
value: *mut c_void,
|
||||||
size: *mut socklen_t,
|
size: *mut socklen_t,
|
||||||
) -> c_int {
|
) -> CIntZeroResult {
|
||||||
let _ = fd;
|
if value.is_null() || size.is_null() {
|
||||||
let _ = level;
|
error::errno = Errno::EINVAL;
|
||||||
let _ = name;
|
return CIntZeroResult::ERROR;
|
||||||
let _ = value;
|
}
|
||||||
let _ = size;
|
|
||||||
todo!()
|
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]
|
#[no_mangle]
|
||||||
@ -25,11 +77,76 @@ unsafe extern "C" fn setsockopt(
|
|||||||
name: c_int,
|
name: c_int,
|
||||||
value: *const c_void,
|
value: *const c_void,
|
||||||
size: socklen_t,
|
size: socklen_t,
|
||||||
) -> c_int {
|
) -> CIntZeroResult {
|
||||||
let _ = fd;
|
if value.is_null() {
|
||||||
let _ = level;
|
error::errno = Errno::EINVAL;
|
||||||
let _ = name;
|
return CIntZeroResult::ERROR;
|
||||||
let _ = value;
|
}
|
||||||
let _ = size;
|
|
||||||
todo!()
|
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::{
|
use crate::{
|
||||||
error::{self, CFdResult, CResult},
|
error::{self, CFdResult, CIntCountResult, CIntZeroResult, CResult, ResultExt, TryFromExt},
|
||||||
headers::{
|
headers::{
|
||||||
errno::Errno,
|
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]
|
#[no_mangle]
|
||||||
unsafe extern "C" fn accept(fd: c_int, remote: *mut sockaddr, len: *mut socklen_t) -> c_int {
|
unsafe extern "C" fn accept(fd: c_int, remote: *mut sockaddr, len: *mut socklen_t) -> CFdResult {
|
||||||
let _ = fd;
|
let listener_fd = RawFd::e_try_from(fd)?;
|
||||||
let _ = remote;
|
let mut address = MaybeUninit::uninit();
|
||||||
let _ = len;
|
let stream_fd = syscall::accept(listener_fd, &mut address).e_map_err(Errno::from)?;
|
||||||
todo!()
|
|
||||||
|
if !remote.is_null() && !len.is_null() {
|
||||||
|
let address = address.assume_init();
|
||||||
|
*len = address.to_c(remote, *len)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
CFdResult::success(stream_fd)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
unsafe extern "C" fn bind(fd: c_int, local: *const sockaddr, len: socklen_t) -> c_int {
|
unsafe extern "C" fn bind(fd: c_int, local: *const sockaddr, len: socklen_t) -> CIntZeroResult {
|
||||||
let _ = fd;
|
let fd = RawFd::e_try_from(fd)?;
|
||||||
let _ = local;
|
let local = local.to_rust(len)?;
|
||||||
let _ = len;
|
syscall::bind(fd, &local).e_map_err(Errno::from)?;
|
||||||
|
CIntZeroResult::SUCCESS
|
||||||
todo!()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
unsafe extern "C" fn connect(fd: c_int, remote: *const sockaddr, len: socklen_t) -> c_int {
|
unsafe extern "C" fn connect(fd: c_int, remote: *const sockaddr, len: socklen_t) -> CIntZeroResult {
|
||||||
let _ = fd;
|
let fd = RawFd::e_try_from(fd)?;
|
||||||
let _ = remote;
|
let remote = remote.to_rust(len)?;
|
||||||
let _ = len;
|
syscall::connect(fd, &remote).e_map_err(Errno::from)?;
|
||||||
todo!()
|
CIntZeroResult::SUCCESS
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
unsafe extern "C" fn getpeername(fd: c_int, remote: *mut sockaddr, len: *mut socklen_t) -> c_int {
|
unsafe extern "C" fn listen(fd: c_int, backlog: c_int) -> CIntZeroResult {
|
||||||
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;
|
|
||||||
let _ = backlog;
|
let _ = backlog;
|
||||||
todo!()
|
let fd = RawFd::e_try_from(fd)?;
|
||||||
|
syscall::listen(fd).e_map_err(Errno::from)?;
|
||||||
|
CIntZeroResult::SUCCESS
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
unsafe extern "C" fn shutdown(fd: c_int, how: c_int) -> c_int {
|
unsafe extern "C" fn shutdown(fd: c_int, how: c_int) -> CIntZeroResult {
|
||||||
let _ = fd;
|
let fd = RawFd::e_try_from(fd)?;
|
||||||
let _ = how;
|
let how = match how {
|
||||||
todo!()
|
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]
|
#[no_mangle]
|
||||||
unsafe extern "C" fn sockatmark(fd: c_int) -> c_int {
|
unsafe extern "C" fn sockatmark(_fd: c_int) -> CIntCountResult {
|
||||||
let _ = fd;
|
error::errno = Errno::EINVAL;
|
||||||
todo!()
|
CIntCountResult::ERROR
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
unsafe extern "C" fn socket(domain: c_int, ty: c_int, proto: c_int) -> CFdResult {
|
unsafe extern "C" fn socket(domain: c_int, ty: c_int, proto: c_int) -> CFdResult {
|
||||||
match (domain, ty, proto) {
|
let ty = match (domain, ty, proto) {
|
||||||
(AF_INET, SOCK_STREAM, 0) => todo!(),
|
(AF_INET, SOCK_STREAM, 0) => rt::SocketType::TcpStream,
|
||||||
(AF_INET, SOCK_DGRAM, 0) => todo!(),
|
(AF_INET, SOCK_DGRAM, 0) => rt::SocketType::UdpPacket,
|
||||||
(_, _, _) => {
|
(_, _, _) => {
|
||||||
yggdrasil_rt::debug_trace!("Unsupported socket({domain}, {ty}, {proto})");
|
yggdrasil_rt::debug_trace!("Unsupported socket({domain}, {ty}, {proto})");
|
||||||
error::errno = Errno::ENOTSUPP;
|
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]
|
#[no_mangle]
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
use core::{ffi::{c_char, c_int, c_long, c_void}, time::Duration};
|
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};
|
use super::sys_types::{suseconds_t, time_t};
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
|
#[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 {
|
impl From<__ygg_timespec_t> for Duration {
|
||||||
fn from(value: __ygg_timespec_t) -> Self {
|
fn from(value: __ygg_timespec_t) -> Self {
|
||||||
Self::new(
|
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