Files
@ 6c04a99de862
Branch filter:
Location: CSY/reowolf/src/ffi/socket_api.rs
6c04a99de862
5.4 KiB
application/rls-services+xml
fleshed out socket api. did bugfix: proto components remember whether they did put/get
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | use super::*;
use atomic_refcell::AtomicRefCell;
use std::{collections::HashMap, ffi::c_void, net::SocketAddr, os::raw::c_int, sync::RwLock};
///////////////////////////////////////////////////////////////////
struct FdAllocator {
next: Option<c_int>,
freed: Vec<c_int>,
}
enum MaybeConnector {
New,
Bound { local_addr: SocketAddr },
Connected { connector: Connector, putter: PortId, getter: PortId },
}
#[derive(Default)]
struct ConnectorStorage {
fd_to_connector: HashMap<c_int, AtomicRefCell<MaybeConnector>>,
fd_allocator: FdAllocator,
}
///////////////////////////////////////////////////////////////////
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 CONNECTOR_STORAGE: RwLock<ConnectorStorage> = Default::default();
}
///////////////////////////////////////////////////////////////////
#[no_mangle]
pub extern "C" fn rw_socket(_domain: c_int, _type: c_int) -> c_int {
// assuming _domain is AF_INET and _type is SOCK_DGRAM
let mut w = if let Ok(w) = CONNECTOR_STORAGE.write() { w } else { return FD_LOCK_POISONED };
let fd = w.fd_allocator.alloc();
w.fd_to_connector.insert(fd, AtomicRefCell::new(MaybeConnector::New));
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) = CONNECTOR_STORAGE.write() { w } else { return FD_LOCK_POISONED };
w.fd_allocator.free(fd);
if w.fd_to_connector.remove(&fd).is_some() {
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 {
use MaybeConnector as Mc;
// assuming _domain is AF_INET and _type is SOCK_DGRAM
let r = if let Ok(r) = CONNECTOR_STORAGE.read() { r } else { return FD_LOCK_POISONED };
let mc = if let Some(mc) = r.fd_to_connector.get(&fd) { mc } else { return BAD_FD };
let mc: &mut Mc = &mut mc.borrow_mut();
let _ = if let Mc::New = mc { () } else { return WRONG_STATE };
*mc = Mc::Bound { local_addr: local_addr.read() };
ERR_OK
}
#[no_mangle]
pub unsafe extern "C" fn rw_connect(
fd: c_int,
peer_addr: *const SocketAddr,
_address_len: usize,
) -> c_int {
use MaybeConnector as Mc;
// assuming _domain is AF_INET and _type is SOCK_DGRAM
let r = if let Ok(r) = CONNECTOR_STORAGE.read() { r } else { return FD_LOCK_POISONED };
let mc = if let Some(mc) = r.fd_to_connector.get(&fd) { mc } else { return BAD_FD };
let mc: &mut Mc = &mut mc.borrow_mut();
let local_addr =
if let Mc::Bound { local_addr } = mc { local_addr } else { return WRONG_STATE };
let peer_addr = peer_addr.read();
let (connector, [putter, getter]) = {
let mut c = Connector::new(
Box::new(DummyLogger),
crate::TRIVIAL_PD.clone(),
Connector::random_id(),
8,
);
let [putter, getter] = c.new_udp_port(*local_addr, peer_addr).unwrap();
(c, [putter, getter])
};
*mc = Mc::Connected { connector, putter, getter };
ERR_OK
}
#[no_mangle]
pub unsafe extern "C" fn rw_send(
fd: c_int,
bytes_ptr: *const c_void,
bytes_len: usize,
_flags: c_int,
) -> isize {
use MaybeConnector as Mc;
// ignoring flags
let r =
if let Ok(r) = CONNECTOR_STORAGE.read() { r } else { return FD_LOCK_POISONED as isize };
let mc = if let Some(mc) = r.fd_to_connector.get(&fd) { mc } else { return BAD_FD as isize };
let mc: &mut Mc = &mut mc.borrow_mut();
let (connector, putter) = if let Mc::Connected { connector, putter, .. } = mc {
(connector, *putter)
} else {
return WRONG_STATE as isize;
};
match connector_put_bytes(connector, putter, bytes_ptr as _, bytes_len) {
ERR_OK => {}
err => return err as isize,
}
connector_sync(connector, -1)
}
#[no_mangle]
pub unsafe extern "C" fn rw_recv(
fd: c_int,
bytes_ptr: *mut c_void,
bytes_len: usize,
_flags: c_int,
) -> isize {
use MaybeConnector as Mc;
// ignoring flags
let r =
if let Ok(r) = CONNECTOR_STORAGE.read() { r } else { return FD_LOCK_POISONED as isize };
let mc = if let Some(mc) = r.fd_to_connector.get(&fd) { mc } else { return BAD_FD as isize };
let mc: &mut Mc = &mut mc.borrow_mut();
let (connector, getter) = if let Mc::Connected { connector, getter, .. } = mc {
(connector, *getter)
} else {
return WRONG_STATE as isize;
};
match connector_get(connector, getter) {
ERR_OK => {}
err => return err as isize,
}
match connector_sync(connector, -1) {
0 => {} // singleton batch index
err => return err as isize,
};
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
}
|