#![allow(clippy::not_unsafe_ptr_arg_deref)]
use std::{
mem,
net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6},
ptr,
time::Duration,
};
use crate::{
Lio,
api::{self, resource::Resource},
net_utils,
};
#[cfg(unix)]
use std::os::fd::{FromRawFd, RawFd};
#[allow(non_camel_case_types)]
pub struct lio_handle_t {
inner: Lio,
}
#[inline]
unsafe fn handle(ptr: *mut lio_handle_t) -> &'static mut lio_handle_t {
unsafe { &mut *ptr }
}
#[cfg(unix)]
unsafe fn fd_to_resource(fd: libc::intptr_t) -> Resource {
unsafe { Resource::from_raw_fd(fd as RawFd) }
}
#[cfg(unix)]
fn resource_to_fd(r: &Resource) -> libc::intptr_t {
use std::os::fd::AsRawFd;
r.as_raw_fd() as libc::intptr_t
}
fn sockaddr_to_socketaddr(
raw_addr_ptr: *const libc::sockaddr,
addr_len: libc::socklen_t,
) -> Option<SocketAddr> {
if raw_addr_ptr.is_null() {
return None;
}
let family = unsafe { *raw_addr_ptr }.sa_family as i32;
match family {
libc::AF_INET => {
if addr_len < mem::size_of::<libc::sockaddr_in>() as libc::socklen_t {
return None;
}
let raw_v4 = raw_addr_ptr as *const libc::sockaddr_in;
let sockaddr_v4 = unsafe { *raw_v4 };
let port = u16::from_be(sockaddr_v4.sin_port);
let ipv4_addr = Ipv4Addr::from(u32::from_be(sockaddr_v4.sin_addr.s_addr));
Some(SocketAddr::V4(SocketAddrV4::new(ipv4_addr, port)))
}
libc::AF_INET6 => {
if addr_len < mem::size_of::<libc::sockaddr_in6>() as libc::socklen_t {
return None;
}
let raw_v6 = raw_addr_ptr as *const libc::sockaddr_in6;
let sockaddr_v6 = unsafe { *raw_v6 };
let port = u16::from_be(sockaddr_v6.sin6_port);
let ipv6_addr = Ipv6Addr::from(sockaddr_v6.sin6_addr.s6_addr);
Some(SocketAddr::V6(SocketAddrV6::new(
ipv6_addr,
port,
u32::from_be(sockaddr_v6.sin6_flowinfo),
u32::from_be(sockaddr_v6.sin6_scope_id),
)))
}
_ => None,
}
}
#[unsafe(no_mangle)]
pub extern "C" fn lio_create(capacity: libc::c_uint) -> *mut lio_handle_t {
match Lio::new(capacity as usize) {
Ok(inner) => Box::into_raw(Box::new(lio_handle_t { inner })),
Err(_) => ptr::null_mut(),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn lio_destroy(lio: *mut lio_handle_t) {
if !lio.is_null() {
drop(unsafe { Box::from_raw(lio) });
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn lio_tick(lio: *mut lio_handle_t) -> libc::c_int {
match unsafe { handle(lio) }.inner.try_run() {
Ok(n) => n as libc::c_int,
Err(_) => -1,
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn lio_shutdown(
lio: *mut lio_handle_t,
fd: libc::intptr_t,
how: libc::c_int,
callback: extern "C" fn(libc::c_int),
) {
let resource = unsafe { fd_to_resource(fd) };
api::shutdown(&resource, how)
.with_lio(&unsafe { handle(lio) }.inner)
.when_done(move |res| {
callback(match res {
Ok(_) => 0,
Err(e) => -e.raw_os_error().unwrap_or(1),
});
std::mem::forget(resource);
});
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn lio_fsync(
lio: *mut lio_handle_t,
fd: libc::intptr_t,
callback: extern "C" fn(libc::c_int),
) {
let resource = unsafe { fd_to_resource(fd) };
api::fsync(&resource).with_lio(&unsafe { handle(lio) }.inner).when_done(
move |res| {
callback(match res {
Ok(_) => 0,
Err(e) => -e.raw_os_error().unwrap_or(1),
});
std::mem::forget(resource);
},
);
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn lio_truncate(
lio: *mut lio_handle_t,
fd: libc::intptr_t,
len: u64,
callback: extern "C" fn(libc::c_int),
) {
let resource = unsafe { fd_to_resource(fd) };
api::truncate(&resource, len)
.with_lio(&unsafe { handle(lio) }.inner)
.when_done(move |res| {
callback(match res {
Ok(_) => 0,
Err(e) => -e.raw_os_error().unwrap_or(1),
});
std::mem::forget(resource);
});
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn lio_write_at(
lio: *mut lio_handle_t,
fd: libc::intptr_t,
buf: *mut u8,
buf_len: usize,
offset: i64,
callback: extern "C" fn(libc::c_int, *mut u8, usize),
) {
let vec = unsafe { Vec::from_raw_parts(buf, buf_len, buf_len) };
let resource = unsafe { fd_to_resource(fd) };
api::write_at(&resource, vec, offset)
.with_lio(&unsafe { handle(lio) }.inner)
.when_done(move |(res, mut buf)| {
let code = match res {
Ok(n) => n,
Err(e) => -e.raw_os_error().unwrap_or(1),
};
let ptr = buf.as_mut_ptr();
let len = buf.len();
std::mem::forget(buf);
callback(code, ptr, len);
std::mem::forget(resource);
});
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn lio_read_at(
lio: *mut lio_handle_t,
fd: libc::intptr_t,
buf: *mut u8,
buf_len: usize,
offset: i64,
callback: extern "C" fn(libc::c_int, *mut u8, usize),
) {
let vec = unsafe { Vec::from_raw_parts(buf, buf_len, buf_len) };
let resource = unsafe { fd_to_resource(fd) };
api::read_at(&resource, vec, offset)
.with_lio(&unsafe { handle(lio) }.inner)
.when_done(move |(res, mut buf)| {
let code = match res {
Ok(n) => n,
Err(e) => -e.raw_os_error().unwrap_or(1),
};
let ptr = buf.as_mut_ptr();
let len = buf.len();
std::mem::forget(buf);
callback(code, ptr, len);
std::mem::forget(resource);
});
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn lio_socket(
lio: *mut lio_handle_t,
domain: libc::c_int,
ty: libc::c_int,
proto: libc::c_int,
callback: extern "C" fn(libc::intptr_t),
) {
api::socket(domain, ty, proto)
.with_lio(&unsafe { handle(lio) }.inner)
.when_done(move |res| {
callback(match res {
Ok(r) => {
let fd = resource_to_fd(&r);
std::mem::forget(r);
fd
}
Err(e) => -e.raw_os_error().unwrap_or(1) as libc::intptr_t,
});
});
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn lio_bind(
lio: *mut lio_handle_t,
fd: libc::intptr_t,
sock: *const libc::sockaddr,
sock_len: libc::socklen_t,
callback: extern "C" fn(libc::c_int),
) {
let addr = match sockaddr_to_socketaddr(sock, sock_len) {
Some(a) => a,
None => {
callback(-libc::EINVAL);
return;
}
};
let resource = unsafe { fd_to_resource(fd) };
api::bind(&resource, addr).with_lio(&unsafe { handle(lio) }.inner).when_done(
move |res| {
callback(match res {
Ok(_) => 0,
Err(e) => -e.raw_os_error().unwrap_or(1),
});
std::mem::forget(resource);
},
);
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn lio_accept(
lio: *mut lio_handle_t,
fd: libc::intptr_t,
callback: extern "C" fn(libc::intptr_t, *const libc::sockaddr_storage),
) {
let resource = unsafe { fd_to_resource(fd) };
api::accept(&resource).with_lio(&unsafe { handle(lio) }.inner).when_done(
move |res| {
let (code, addr_ptr) = match res {
Ok((new_res, addr)) => {
let fd = resource_to_fd(&new_res);
std::mem::forget(new_res);
(
fd,
Box::into_raw(Box::new(net_utils::std_socketaddr_into_libc(addr)))
as *const _,
)
}
Err(e) => {
(-e.raw_os_error().unwrap_or(1) as libc::intptr_t, ptr::null())
}
};
callback(code, addr_ptr);
std::mem::forget(resource);
},
);
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn lio_listen(
lio: *mut lio_handle_t,
fd: libc::intptr_t,
backlog: libc::c_int,
callback: extern "C" fn(libc::c_int),
) {
let resource = unsafe { fd_to_resource(fd) };
api::listen(&resource, backlog)
.with_lio(&unsafe { handle(lio) }.inner)
.when_done(move |res| {
callback(match res {
Ok(_) => 0,
Err(e) => -e.raw_os_error().unwrap_or(1),
});
std::mem::forget(resource);
});
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn lio_send(
lio: *mut lio_handle_t,
fd: libc::intptr_t,
buf: *mut u8,
buf_len: usize,
flags: libc::c_int,
callback: extern "C" fn(libc::c_int, *mut u8, usize),
) {
let vec = unsafe { Vec::from_raw_parts(buf, buf_len, buf_len) };
let resource = unsafe { fd_to_resource(fd) };
api::send(&resource, vec, Some(flags))
.with_lio(&unsafe { handle(lio) }.inner)
.when_done(move |(res, mut buf)| {
let code = match res {
Ok(n) => n,
Err(e) => -e.raw_os_error().unwrap_or(1),
};
let ptr = buf.as_mut_ptr();
let len = buf.len();
std::mem::forget(buf);
callback(code, ptr, len);
std::mem::forget(resource);
});
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn lio_recv(
lio: *mut lio_handle_t,
fd: libc::intptr_t,
buf: *mut u8,
buf_len: usize,
flags: libc::c_int,
callback: extern "C" fn(libc::c_int, *mut u8, usize),
) {
let vec = unsafe { Vec::from_raw_parts(buf, buf_len, buf_len) };
let resource = unsafe { fd_to_resource(fd) };
api::recv(&resource, vec, Some(flags))
.with_lio(&unsafe { handle(lio) }.inner)
.when_done(move |(res, mut buf)| {
let code = match res {
Ok(n) => n,
Err(e) => -e.raw_os_error().unwrap_or(1),
};
let ptr = buf.as_mut_ptr();
let len = buf.len();
std::mem::forget(buf);
callback(code, ptr, len);
std::mem::forget(resource);
});
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn lio_close(
lio: *mut lio_handle_t,
fd: libc::intptr_t,
callback: extern "C" fn(libc::c_int),
) {
api::close(fd as RawFd).with_lio(&unsafe { handle(lio) }.inner).when_done(
move |res| {
callback(match res {
Ok(_) => 0,
Err(e) => -e.raw_os_error().unwrap_or(1),
});
},
);
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn lio_timeout(
lio: *mut lio_handle_t,
millis: libc::c_uint,
callback: extern "C" fn(libc::c_int),
) {
api::timeout(Duration::from_millis(millis as u64))
.with_lio(&unsafe { handle(lio) }.inner)
.when_done(move |res| {
callback(match res {
Ok(_) => 0,
Err(e) => -e.raw_os_error().unwrap_or(1),
});
});
}