Files @ 1db6ec21a437
Branch filter:

Location: CSY/reowolf/src/ffi/socket_api.rs - annotation

1db6ec21a437 8.5 KiB application/rls-services+xml Show Source Show as Raw Download as Raw
Christopher Esterhuyse
more elegant on-demand native branch indexing with a speculative var
4db4ea6f0eb3
6c04a99de862
700221108e9f
700221108e9f
700221108e9f
700221108e9f
700221108e9f
700221108e9f
700221108e9f
bdcf814bde8c
bdcf814bde8c
bdcf814bde8c
6c04a99de862
6c04a99de862
bdcf814bde8c
700221108e9f
700221108e9f
700221108e9f
700221108e9f
700221108e9f
700221108e9f
700221108e9f
700221108e9f
700221108e9f
700221108e9f
700221108e9f
700221108e9f
bdcf814bde8c
bdcf814bde8c
1db6ec21a437
1db6ec21a437
bdcf814bde8c
bdcf814bde8c
700221108e9f
700221108e9f
700221108e9f
700221108e9f
bdcf814bde8c
7b9df91324ad
bdcf814bde8c
bdcf814bde8c
bdcf814bde8c
bdcf814bde8c
bdcf814bde8c
bdcf814bde8c
bdcf814bde8c
bdcf814bde8c
bdcf814bde8c
6c04a99de862
bdcf814bde8c
bdcf814bde8c
bdcf814bde8c
bdcf814bde8c
bdcf814bde8c
bdcf814bde8c
bdcf814bde8c
bdcf814bde8c
bdcf814bde8c
6c04a99de862
bdcf814bde8c
bdcf814bde8c
bdcf814bde8c
bdcf814bde8c
1db6ec21a437
bdcf814bde8c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
bdcf814bde8c
bdcf814bde8c
bdcf814bde8c
7b9df91324ad
700221108e9f
1db6ec21a437
bdcf814bde8c
700221108e9f
1db6ec21a437
bdcf814bde8c
bdcf814bde8c
bdcf814bde8c
bdcf814bde8c
6c04a99de862
bdcf814bde8c
1db6ec21a437
1db6ec21a437
1db6ec21a437
4db4ea6f0eb3
bdcf814bde8c
4db4ea6f0eb3
bdcf814bde8c
bdcf814bde8c
bdcf814bde8c
bdcf814bde8c
7b9df91324ad
6c04a99de862
6c04a99de862
6c04a99de862
7b9df91324ad
bdcf814bde8c
1db6ec21a437
1db6ec21a437
b747c570a11c
b747c570a11c
700221108e9f
700221108e9f
700221108e9f
700221108e9f
700221108e9f
700221108e9f
700221108e9f
700221108e9f
700221108e9f
1db6ec21a437
1db6ec21a437
700221108e9f
700221108e9f
4db4ea6f0eb3
bdcf814bde8c
bdcf814bde8c
bdcf814bde8c
6c04a99de862
6c04a99de862
6c04a99de862
bdcf814bde8c
bdcf814bde8c
bdcf814bde8c
1db6ec21a437
1db6ec21a437
b747c570a11c
b747c570a11c
b747c570a11c
bdcf814bde8c
700221108e9f
bdcf814bde8c
6c04a99de862
6c04a99de862
6c04a99de862
6c04a99de862
7b9df91324ad
7b9df91324ad
6c04a99de862
1db6ec21a437
1db6ec21a437
b747c570a11c
b747c570a11c
b747c570a11c
6c04a99de862
6c04a99de862
6c04a99de862
6c04a99de862
6c04a99de862
6c04a99de862
6c04a99de862
6c04a99de862
6c04a99de862
6c04a99de862
1db6ec21a437
1db6ec21a437
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
1db6ec21a437
1db6ec21a437
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
1db6ec21a437
1db6ec21a437
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
b747c570a11c
6c04a99de862
b747c570a11c
bdcf814bde8c
use super::*;

use std::{
    collections::HashMap,
    ffi::c_void,
    net::{Ipv4Addr, SocketAddr, SocketAddrV4},
    os::raw::c_int,
    sync::RwLock,
};
///////////////////////////////////////////////////////////////////

struct FdAllocator {
    next: Option<c_int>,
    freed: Vec<c_int>,
}
struct ConnectorBound {
    connector: Connector,
    putter: PortId,
    getter: PortId,
}
struct MaybeConnector {
    // invariants:
    // 1. connector is a upd-socket singleton
    // 2. putter and getter are ports in the native interface with the appropriate polarities
    // 3. peer_addr always mirrors connector's single udp socket's connect addr. both are overwritten together.
    peer_addr: SocketAddr,
    connector_bound: Option<ConnectorBound>,
}
#[derive(Default)]
struct FdcStorage {
    fd_to_c: HashMap<c_int, RwLock<MaybeConnector>>,
    fd_allocator: FdAllocator,
}
fn trivial_peer_addr() -> SocketAddr {
    // SocketAddrV4::new isn't a constant-time func
    SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), 0))
}
///////////////////////////////////////////////////////////////////

impl Default for FdAllocator {
    fn default() -> Self {
        Self {
            next: Some(0), // positive values used only
            freed: vec![],
        }
    }
}
impl FdAllocator {
    fn alloc(&mut self) -> c_int {
        if let Some(fd) = self.freed.pop() {
            return fd;
        }
        if let Some(fd) = self.next {
            self.next = fd.checked_add(1);
            return fd;
        }
        panic!("No more Connector FDs to allocate!")
    }
    fn free(&mut self, fd: c_int) {
        self.freed.push(fd);
    }
}
lazy_static::lazy_static! {
    static ref FDC_STORAGE: RwLock<FdcStorage> = Default::default();
}
impl MaybeConnector {
    fn connect(&mut self, peer_addr: SocketAddr) -> c_int {
        self.peer_addr = peer_addr;
        if let Some(ConnectorBound { connector, .. }) = &mut self.connector_bound {
            if connector.get_mut_udp_sock(0).unwrap().connect(peer_addr).is_err() {
                return CONNECT_FAILED;
            }
        }
        ERR_OK
    }
    unsafe fn send(&mut self, bytes_ptr: *const c_void, bytes_len: usize) -> isize {
        if let Some(ConnectorBound { connector, putter, .. }) = &mut self.connector_bound {
            match connector_put_bytes(connector, *putter, bytes_ptr as _, bytes_len) {
                ERR_OK => connector_sync(connector, -1),
                err => err as isize,
            }
        } else {
            WRONG_STATE as isize // not bound!
        }
    }
    unsafe fn recv(&mut self, bytes_ptr: *const c_void, bytes_len: usize) -> isize {
        if let Some(ConnectorBound { connector, getter, .. }) = &mut self.connector_bound {
            connector_get(connector, *getter);
            match connector_sync(connector, -1) {
                0 => {
                    // batch index 0 means OK
                    let slice = connector.gotten(*getter).unwrap().as_slice();
                    let copied_bytes = slice.len().min(bytes_len);
                    std::ptr::copy_nonoverlapping(
                        slice.as_ptr(),
                        bytes_ptr as *mut u8,
                        copied_bytes,
                    );
                    copied_bytes as isize
                }
                err => return err as isize,
            }
        } else {
            WRONG_STATE as isize // not bound!
        }
    }
}
///////////////////////////////////////////////////////////////////

#[no_mangle]
pub extern "C" fn rw_socket(_domain: c_int, _type: c_int) -> c_int {
    // ignoring domain and type
    let mut w = if let Ok(w) = FDC_STORAGE.write() { w } else { return FD_LOCK_POISONED };
    let fd = w.fd_allocator.alloc();
    let mc = MaybeConnector { peer_addr: trivial_peer_addr(), connector_bound: None };
    w.fd_to_c.insert(fd, RwLock::new(mc));
    fd
}

#[no_mangle]
pub extern "C" fn rw_close(fd: c_int, _how: c_int) -> c_int {
    // ignoring HOW
    let mut w = if let Ok(w) = FDC_STORAGE.write() { w } else { return FD_LOCK_POISONED };
    if w.fd_to_c.remove(&fd).is_some() {
        w.fd_allocator.free(fd);
        ERR_OK
    } else {
        CLOSE_FAIL
    }
}

#[no_mangle]
pub unsafe extern "C" fn rw_bind(
    fd: c_int,
    local_addr: *const SocketAddr,
    _addr_len: usize,
) -> c_int {
    // assuming _domain is AF_INET and _type is SOCK_DGRAM
    let r = if let Ok(r) = FDC_STORAGE.read() { r } else { return FD_LOCK_POISONED };
    let mc = if let Some(mc) = r.fd_to_c.get(&fd) { mc } else { return BAD_FD };
    let mut mc = if let Ok(mc) = mc.write() { mc } else { return FD_LOCK_POISONED };
    let mc: &mut MaybeConnector = &mut mc;
    if mc.connector_bound.is_some() {
        return WRONG_STATE;
    }
    mc.connector_bound = {
        let mut connector = Connector::new(
            Box::new(crate::DummyLogger),
            crate::TRIVIAL_PD.clone(),
            Connector::random_id(),
        );
        let [putter, getter] =
            connector.new_udp_mediator_component(local_addr.read(), mc.peer_addr).unwrap();
        Some(ConnectorBound { connector, putter, getter })
    };
    ERR_OK
}

#[no_mangle]
pub unsafe extern "C" fn rw_connect(
    fd: c_int,
    peer_addr: *const SocketAddr,
    _address_len: usize,
) -> c_int {
    // assuming _domain is AF_INET and _type is SOCK_DGRAM
    let r = if let Ok(r) = FDC_STORAGE.read() { r } else { return FD_LOCK_POISONED };
    let mc = if let Some(mc) = r.fd_to_c.get(&fd) { mc } else { return BAD_FD };
    let mut mc = if let Ok(mc) = mc.write() { mc } else { return FD_LOCK_POISONED };
    let mc: &mut MaybeConnector = &mut mc;
    mc.connect(peer_addr.read())
}

#[no_mangle]
pub unsafe extern "C" fn rw_send(
    fd: c_int,
    bytes_ptr: *const c_void,
    bytes_len: usize,
    _flags: c_int,
) -> isize {
    // ignoring flags
    let r = if let Ok(r) = FDC_STORAGE.read() { r } else { return FD_LOCK_POISONED as isize };
    let mc = if let Some(mc) = r.fd_to_c.get(&fd) { mc } else { return BAD_FD as isize };
    let mut mc = if let Ok(mc) = mc.write() { mc } else { return FD_LOCK_POISONED as isize };
    let mc: &mut MaybeConnector = &mut mc;
    mc.send(bytes_ptr, bytes_len)
}

#[no_mangle]
pub unsafe extern "C" fn rw_recv(
    fd: c_int,
    bytes_ptr: *mut c_void,
    bytes_len: usize,
    _flags: c_int,
) -> isize {
    // ignoring flags
    let r = if let Ok(r) = FDC_STORAGE.read() { r } else { return FD_LOCK_POISONED as isize };
    let mc = if let Some(mc) = r.fd_to_c.get(&fd) { mc } else { return BAD_FD as isize };
    let mut mc = if let Ok(mc) = mc.write() { mc } else { return FD_LOCK_POISONED as isize };
    let mc: &mut MaybeConnector = &mut mc;
    mc.recv(bytes_ptr, bytes_len)
}

#[no_mangle]
pub unsafe extern "C" fn rw_sendto(
    fd: c_int,
    bytes_ptr: *mut c_void,
    bytes_len: usize,
    _flags: c_int,
    peer_addr: *const SocketAddr,
    _addr_len: usize,
) -> isize {
    let r = if let Ok(r) = FDC_STORAGE.read() { r } else { return FD_LOCK_POISONED as isize };
    let mc = if let Some(mc) = r.fd_to_c.get(&fd) { mc } else { return BAD_FD as isize };
    let mut mc = if let Ok(mc) = mc.write() { mc } else { return FD_LOCK_POISONED as isize };
    let mc: &mut MaybeConnector = &mut mc;
    // copy currently connected peer addr
    let connected = mc.peer_addr;
    // connect to given peer_addr
    match mc.connect(peer_addr.read()) {
        e if e != ERR_OK => return e as isize,
        _ => {}
    }
    // send
    let ret = mc.send(bytes_ptr, bytes_len);
    // restore connected peer addr
    match mc.connect(connected) {
        e if e != ERR_OK => return e as isize,
        _ => {}
    }
    ret
}

#[no_mangle]
#[no_mangle]
pub unsafe extern "C" fn rw_recvfrom(
    fd: c_int,
    bytes_ptr: *mut c_void,
    bytes_len: usize,
    _flags: c_int,
    peer_addr: *const SocketAddr,
    _addr_len: usize,
) -> isize {
    let r = if let Ok(r) = FDC_STORAGE.read() { r } else { return FD_LOCK_POISONED as isize };
    let mc = if let Some(mc) = r.fd_to_c.get(&fd) { mc } else { return BAD_FD as isize };
    let mut mc = if let Ok(mc) = mc.write() { mc } else { return FD_LOCK_POISONED as isize };
    let mc: &mut MaybeConnector = &mut mc;
    // copy currently connected peer addr
    let connected = mc.peer_addr;
    // connect to given peer_addr
    match mc.connect(peer_addr.read()) {
        e if e != ERR_OK => return e as isize,
        _ => {}
    }
    // send
    let ret = mc.send(bytes_ptr, bytes_len);
    // restore connected peer addr
    match mc.connect(connected) {
        e if e != ERR_OK => return e as isize,
        _ => {}
    }
    ret
}