use core::{
ffi::{c_char, c_int, c_void},
mem::size_of,
};
use ax_posix_api::ctypes::{
FIONBIO, IPPROTO_TCP, SO_ERROR, SO_KEEPALIVE, SO_LINGER, SO_RCVBUF, SO_RCVTIMEO, SO_REUSEADDR,
SO_SNDBUF, SO_SNDTIMEO, SOL_SOCKET, TCP_NODELAY, addrinfo, nfds_t, pollfd, sockaddr, socklen_t,
timeval,
};
use log::info;
use super::io::set_errno;
#[unsafe(no_mangle)]
pub fn sys_freeaddrinfo(addr_info: *mut addrinfo) {
info!("[sys_freeaddrinfo] addr_info: {:p}", addr_info);
unsafe { ax_posix_api::sys_freeaddrinfo(addr_info) }
}
#[unsafe(no_mangle)]
pub fn sys_getaddrinfo(
nodename: *const c_char,
servname: *const c_char,
hints: *const addrinfo,
res: *mut *mut addrinfo,
) -> i32 {
info!(
"[sys_getaddrinfo] nodename: {:?}, servname: {:?}",
nodename, servname
);
let result = unsafe { ax_posix_api::sys_getaddrinfo(nodename, servname, hints, res) };
if result > 0 {
0
} else {
-1
}
}
#[unsafe(no_mangle)]
pub fn sys_send(s: i32, mem: *const c_void, len: usize, flags: i32) -> isize {
info!("[sys_send] socket: {}, len: {}, flags: {}", s, len, flags);
ax_posix_api::sys_send(s, mem, len, flags)
}
#[unsafe(no_mangle)]
pub fn sys_socket(domain: i32, type_: i32, protocol: i32) -> i32 {
info!(
"[sys_socket] domain: {}, type: {}, protocol: {}",
domain, type_, protocol
);
ax_posix_api::sys_socket(domain, type_, protocol)
}
#[unsafe(no_mangle)]
pub fn sys_connect(socket_fd: i32, name: *const sockaddr, namelen: socklen_t) -> i32 {
info!(
"[sys_connect] socket_fd: {}, namelen: {}",
socket_fd, namelen
);
info!("name: {:?}", unsafe { *name });
let ret = ax_posix_api::sys_connect(socket_fd, name, namelen);
if ret == -ax_errno::LinuxError::EAGAIN.code() {
-ax_errno::LinuxError::EINPROGRESS.code()
} else {
ret
}
}
#[unsafe(no_mangle)]
pub fn sys_recv(socket: i32, buf: *mut u8, len: usize, flags: i32) -> isize {
info!(
"[sys_recv] socket: {}, len: {}, flags: {}",
socket, len, flags
);
ax_posix_api::sys_recv(socket, buf as _, len, flags)
}
#[unsafe(no_mangle)]
pub fn sys_listen(socket_fd: i32, backlog: i32) -> i32 {
info!(
"[sys_listen] socket_fd: {}, backlog: {}",
socket_fd, backlog
);
ax_posix_api::sys_listen(socket_fd, backlog)
}
#[unsafe(no_mangle)]
pub fn sys_bind(socket_fd: i32, name: *const sockaddr, namelen: socklen_t) -> i32 {
info!("[sys_bind] socket_fd: {}, namelen: {}", socket_fd, namelen);
ax_posix_api::sys_bind(socket_fd, name, namelen)
}
#[unsafe(no_mangle)]
pub fn sys_getsockname(socket_fd: i32, name: *mut sockaddr, namelen: *mut socklen_t) -> i32 {
info!(
"[sys_getsockname] socket_fd: {}, namelen: {:p}",
socket_fd, namelen
);
unsafe { ax_posix_api::sys_getsockname(socket_fd, name, namelen) }
}
#[unsafe(no_mangle)]
pub fn sys_accept(socket_fd: i32, addr: *mut sockaddr, addrlen: *mut socklen_t) -> i32 {
info!(
"[sys_accept] socket_fd: {}, addrlen: {:p}",
socket_fd, addrlen
);
unsafe { ax_posix_api::sys_accept(socket_fd, addr, addrlen) }
}
#[unsafe(no_mangle)]
pub fn sys_setsockopt(
socket_fd: i32,
level: i32,
optname: i32,
optval: *const c_void,
optlen: socklen_t,
) -> i32 {
info!(
"[setsockopt] socket_fd: {}, level: {}, optname: {}, optlen: {}",
socket_fd, level, optname, optlen
);
unsafe { ax_posix_api::sys_setsockopt(socket_fd, level, optname, optval, optlen) }
}
#[unsafe(no_mangle)]
pub fn sys_getpeername(socket_fd: i32, addr: *mut sockaddr, addrlen: *mut socklen_t) -> i32 {
info!(
"[sys_getpeername] socket_fd: {}, addrlen: {:p}",
socket_fd, addrlen
);
unsafe { ax_posix_api::sys_getpeername(socket_fd, addr, addrlen) }
}
#[unsafe(no_mangle)]
pub fn sys_shutdown(socket_fd: i32, how: i32) -> i32 {
info!("[sys_shutdown] socket_fd: {}, how: {}", socket_fd, how);
ax_posix_api::sys_shutdown(socket_fd, how)
}
#[unsafe(no_mangle)]
pub fn sys_ioctl(fd: i32, cmd: i32, argp: *mut c_void) -> i32 {
info!("[sys_ioctl] fd: {}, cmd: {:#x}", fd, cmd);
if cmd == FIONBIO {
if argp.is_null() {
return -ax_errno::LinuxError::EFAULT.code();
}
let val = unsafe { *(argp as *const c_int) };
let nonblocking = val != 0;
info!("[sys_ioctl] FIONBIO: nonblocking={}", nonblocking);
match ax_posix_api::sys_fcntl(
fd,
ax_posix_api::ctypes::F_SETFL as c_int,
if nonblocking {
ax_posix_api::ctypes::O_NONBLOCK as usize
} else {
0
},
) {
r if r >= 0 => 0,
r => r,
}
} else {
info!("[sys_ioctl] unsupported cmd: {:#x}", cmd);
-ax_errno::LinuxError::EINVAL.code()
}
}
#[unsafe(no_mangle)]
pub fn sys_poll(fds: *mut pollfd, nfds: nfds_t, timeout: i32) -> i32 {
info!(
"[sys_poll] fds: {:p}, nfds: {}, timeout: {}ms",
fds, nfds, timeout
);
let ret = ax_posix_api::sys_poll(fds, nfds, timeout);
if ret < 0 {
set_errno(-ret);
-1
} else {
ret
}
}
#[unsafe(no_mangle)]
pub fn sys_getsockopt(
socket_fd: i32,
level: i32,
optname: i32,
optval: *mut c_void,
optlen: *mut socklen_t,
) -> i32 {
info!(
"[sys_getsockopt] socket_fd: {}, level: {}, optname: {:#x}",
socket_fd, level, optname
);
if optval.is_null() || optlen.is_null() {
return -ax_errno::LinuxError::EFAULT.code();
}
if level == SOL_SOCKET && optname == SO_ERROR {
let val: c_int = 0;
write_sockopt(optval, optlen, &val)
} else if level == SOL_SOCKET && (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO) {
let tv = timeval {
tv_sec: 0,
tv_usec: 0,
};
write_sockopt(optval, optlen, &tv)
} else if level == SOL_SOCKET && optname == SO_LINGER {
let val = ax_posix_api::ctypes::linger {
l_onoff: 0,
l_linger: 0,
};
write_sockopt(optval, optlen, &val)
} else if level == SOL_SOCKET && (optname == SO_REUSEADDR || optname == SO_KEEPALIVE) {
let val: c_int = 0;
write_sockopt(optval, optlen, &val)
} else if level == SOL_SOCKET && (optname == SO_SNDBUF || optname == SO_RCVBUF) {
let val: c_int = 64 * 1024; write_sockopt(optval, optlen, &val)
} else if level == IPPROTO_TCP as i32 && optname == TCP_NODELAY {
let val: c_int = 0;
write_sockopt(optval, optlen, &val)
} else {
info!(
"[sys_getsockopt] unsupported: level={}, optname={:#x}",
level, optname
);
-ax_errno::LinuxError::ENOPROTOOPT.code()
}
}
fn write_sockopt<T: Copy>(optval: *mut c_void, optlen: *mut socklen_t, val: &T) -> i32 {
let len = size_of::<T>();
unsafe {
if (*optlen as usize) < len {
return -ax_errno::LinuxError::EINVAL.code();
}
core::ptr::copy_nonoverlapping(val as *const T as *const u8, optval as *mut u8, len);
*optlen = len as socklen_t;
}
0
}