use std::ffi::{self, c_char};
use crate::{TOKIO_RUNTIME, ffi_guard, util};
pub struct tcp_listener(tailscale::netstack::TcpListener);
impl tcp_listener {
pub(crate) fn new(inner: tailscale::netstack::TcpListener) -> Self {
tcp_listener(inner)
}
}
pub struct tcp_stream(tailscale::netstack::TcpStream);
#[unsafe(no_mangle)]
pub extern "C" fn ts_tcp_listen(
dev: &crate::device,
addr: &crate::sockaddr,
) -> Option<Box<tcp_listener>> {
ffi_guard(move || {
let addr = addr.try_into().ok()?;
match TOKIO_RUNTIME.block_on(dev.0.tcp_listen(addr)) {
Ok(sock) => Some(Box::new(tcp_listener(sock))),
Err(e) => {
tracing::error!(err = %e, "tcp listen");
None
}
}
})
}
#[unsafe(no_mangle)]
pub extern "C" fn ts_tcp_accept(listener: &tcp_listener) -> Option<Box<tcp_stream>> {
ffi_guard(move || match listener.0.accept_blocking() {
Ok(sock) => Some(Box::new(tcp_stream(sock))),
Err(e) => {
tracing::error!(err = %e, "tcp accept");
None
}
})
}
#[unsafe(no_mangle)]
pub extern "C" fn ts_tcp_listener_local_addr(listener: &tcp_listener) -> crate::sockaddr {
ffi_guard(move || listener.0.local_addr().into())
}
#[unsafe(no_mangle)]
pub extern "C" fn ts_tcp_close_listener(sock: Box<tcp_listener>) {
ffi_guard(move || drop(sock))
}
#[unsafe(no_mangle)]
pub extern "C" fn ts_tcp_connect(
dev: &crate::device,
remote: &crate::sockaddr,
) -> Option<Box<tcp_stream>> {
ffi_guard(move || {
let addr = remote.try_into().ok()?;
match TOKIO_RUNTIME.block_on(dev.0.tcp_connect(addr)) {
Ok(sock) => Some(Box::new(tcp_stream(sock))),
Err(e) => {
tracing::error!(err = %e, "binding sock");
None
}
}
})
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn ts_connect_by_name(
dev: &crate::device,
name: *const c_char,
port: u16,
) -> Option<Box<tcp_stream>> {
ffi_guard(move || {
let name = unsafe { util::str(name) }?;
match TOKIO_RUNTIME.block_on(dev.0.connect_by_name(name, port)) {
Ok(sock) => Some(Box::new(tcp_stream(sock))),
Err(e) => {
tracing::error!(err = %e, "connect by name");
None
}
}
})
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn ts_tcp_send(
stream: &tcp_stream,
buf: *const u8,
len: usize,
) -> ffi::c_int {
ffi_guard(move || {
let b = unsafe { core::slice::from_raw_parts(buf, len) };
match stream.0.send_blocking(b) {
Err(e) => {
tracing::error!(err = %e, "tcp accept");
-1
}
Ok(n) => n as _,
}
})
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn ts_tcp_recv(stream: &tcp_stream, buf: *mut u8, len: usize) -> ffi::c_int {
ffi_guard(move || {
let b = unsafe { core::slice::from_raw_parts_mut(buf, len) };
match stream.0.recv_blocking(b) {
Err(e) => {
tracing::error!(err = %e, "tcp accept");
-1
}
Ok(read) => read as _,
}
})
}
#[unsafe(no_mangle)]
pub extern "C" fn ts_tcp_local_addr(stream: &tcp_stream) -> crate::sockaddr {
ffi_guard(move || stream.0.local_addr().into())
}
#[unsafe(no_mangle)]
pub extern "C" fn ts_tcp_remote_addr(stream: &tcp_stream) -> crate::sockaddr {
ffi_guard(move || stream.0.remote_addr().into())
}
#[unsafe(no_mangle)]
pub extern "C" fn ts_tcp_close(sock: Box<tcp_stream>) {
ffi_guard(move || {
drop(sock);
})
}