Changeset - 4bf1367cd8a1
[Not reviewed]
0 3 0
Christopher Esterhuyse - 5 years ago 2020-07-24 11:48:07
christopher.esterhuyse@gmail.com
decluttered global namespace of consts in C FFI. added examples for interop programming
3 files changed with 59 insertions and 83 deletions:
0 comments (0 inline, 0 general)
reowolf.h
Show inline comments
 
/* CBindgen generated */
 

	
 
#ifndef REOWOLF_HEADER_DEFINED
 
#define REOWOLF_HEADER_DEFINED
 

	
 
#include <stdarg.h>
 
#include <stdbool.h>
 
#include <stdint.h>
 
#include <stdlib.h>
 

	
 
#define BAD_FD -5
 
#define RW_BAD_FD -5
 

	
 
#define CC_MAP_LOCK_POISONED -3
 
#define RW_BAD_SOCKADDR -8
 

	
 
#define CLOSE_FAIL -4
 
#define RW_CLOSE_FAIL -4
 

	
 
#define CONNECT_FAILED -6
 
#define RW_CONNECT_FAILED -6
 

	
 
#define ERR_OK 0
 
#define RW_LOCK_POISONED -3
 

	
 
#define ERR_REOWOLF -1
 
#define RW_OK 0
 

	
 
#define WOULD_BLOCK -7
 
#define RW_TL_ERR -1
 

	
 
#define WRONG_STATE -2
 
#define RW_WOULD_BLOCK -7
 

	
 
#define RW_WRONG_STATE -2
 

	
 
typedef enum {
 
  EndpointPolarity_Active,
 
  EndpointPolarity_Passive,
 
} EndpointPolarity;
 

	
 
typedef enum {
 
  Polarity_Putter,
 
  Polarity_Getter,
 
} Polarity;
 

	
 
typedef struct Arc_ProtocolDescription Arc_ProtocolDescription;
 

	
 
typedef struct Connector Connector;
 

	
 
typedef uint32_t ConnectorId;
 

	
 
typedef uint32_t U32Suffix;
 

	
 
typedef struct {
 
  ConnectorId connector_id;
 
  U32Suffix u32_suffix;
 
} Id;
 

	
 
typedef Id PortId;
 

	
 
typedef struct {
 
  uint8_t ipv4[4];
 
  uint16_t port;
 
} FfiSocketAddr;
 

	
 
/**
 
 * Given
 
 * - an initialized connector in setup or connecting state,
 
 * - a string slice for the component's identifier in the connector's configured protocol description,
 
 * - a set of ports (represented as a slice; duplicates are ignored) in the native component's interface,
 
 * the connector creates a new (internal) protocol component C, such that the set of native ports are moved to C.
 
 * Usable in {setup, communication} states.
 
 */
 
int connector_add_component(Connector *connector,
 
                            const uint8_t *ident_ptr,
 
                            uintptr_t ident_len,
 
                            const PortId *ports_ptr,
 
                            uintptr_t ports_len);
 

	
 
/**
 
 * Given
 
 * - an initialized connector in setup or connecting state,
 
 * - a utf-8 encoded socket address,
 
 * - the logical polarity of P,
 
 * - the "physical" polarity in {Active, Passive} of the endpoint through which P's peer will be discovered,
 
 * returns P, a port newly added to the native interface.
 
 */
 
int connector_add_net_port(Connector *connector,
 
                           PortId *port,
 
                           FfiSocketAddr addr,
 
                           Polarity port_polarity,
 
                           EndpointPolarity endpoint_polarity);
 

	
 
/**
 
 * Given an initialized connector in setup or connecting state,
 
 * - Creates a new directed port pair with logical channel putter->getter,
 
 * - adds the ports to the native component's interface,
 
 * - and returns them using the given out pointers.
 
 * Usable in {setup, communication} states.
 
 */
 
void connector_add_port_pair(Connector *connector, PortId *out_putter, PortId *out_getter);
 

	
 
/**
 
 * Given
 
 * - an initialized connector in setup or connecting state,
 
 * - a utf-8 encoded BIND socket addresses (i.e., "local"),
 
 * - a utf-8 encoded CONNECT socket addresses (i.e., "peer"),
 
 * returns [P, G] via out pointers [putter, getter],
 
 * - where P is a Putter port that sends messages into the socket
 
 * - where G is a Getter port that recvs messages from the socket
 
 */
 
int connector_add_udp_port_pair(Connector *connector,
 
int connector_add_udp_mediator_component(Connector *connector,
 
                                         PortId *putter,
 
                                         PortId *getter,
 
                                         FfiSocketAddr local_addr,
 
                                         FfiSocketAddr peer_addr);
 

	
 
/**
 
 * Connects this connector to the distributed system of connectors reachable through endpoints,
 
 * Usable in setup state, and changes the state to communication.
 
 */
 
int connector_connect(Connector *connector, int64_t timeout_millis);
 

	
 
/**
 
 * Destroys the given a pointer to the connector on the heap, freeing its resources.
 
 * Usable in {setup, communication} states.
 
 */
 
void connector_destroy(Connector *connector);
 

	
 
int connector_get(Connector *connector, PortId port);
 

	
 
const uint8_t *connector_gotten_bytes(Connector *connector, PortId port, uintptr_t *out_len);
 

	
 
/**
 
 * Initializes `out` with a new connector using the given protocol description as its configuration.
 
 * The connector uses the given (internal) connector ID.
 
 */
 
Connector *connector_new(const Arc_ProtocolDescription *pd);
 

	
 
Connector *connector_new_logging(const Arc_ProtocolDescription *pd,
 
                                 const uint8_t *path_ptr,
 
                                 uintptr_t path_len);
 

	
 
intptr_t connector_next_batch(Connector *connector);
 

	
 
void connector_print_debug(Connector *connector);
 

	
 
/**
 
 * Convenience function combining the functionalities of
 
 * "payload_new" with "connector_put_payload".
 
 */
 
int connector_put_bytes(Connector *connector,
 
                        PortId port,
 
                        const uint8_t *bytes_ptr,
 
                        uintptr_t bytes_len);
 

	
 
intptr_t connector_sync(Connector *connector, int64_t timeout_millis);
 

	
 
/**
 
 * Given an initialized protocol description, initializes `out` with a clone which can be independently created or destroyed.
 
 */
 
Arc_ProtocolDescription *protocol_description_clone(const Arc_ProtocolDescription *pd);
 

	
 
/**
 
 * Destroys the given initialized protocol description and frees its resources.
 
 */
 
void protocol_description_destroy(Arc_ProtocolDescription *pd);
 

	
 
/**
 
 * Parses the utf8-encoded string slice to initialize a new protocol description object.
 
 * - On success, initializes `out` and returns 0
 
 * - On failure, stores an error string (see `reowolf_error_peek`) and returns -1
 
 */
 
Arc_ProtocolDescription *protocol_description_parse(const uint8_t *pdl, uintptr_t pdl_len);
 

	
 
/**
 
 * Returns length (via out pointer) and pointer (via return value) of the last Reowolf error.
 
 * - pointer is NULL iff there was no last error
 
 * - data at pointer is null-delimited
 
 * - len does NOT include the length of the null-delimiter
 
 * If len is NULL, it will not written to.
 
 */
 
const uint8_t *reowolf_error_peek(uintptr_t *len);
 

	
 
int rw_bind(int fd, const SocketAddr *local_addr, uintptr_t _addr_len);
 

	
 
int rw_close(int fd, int _how);
 

	
 
int rw_connect(int fd, const SocketAddr *peer_addr, uintptr_t _address_len);
 

	
 
intptr_t rw_recv(int fd, void *bytes_ptr, uintptr_t bytes_len, int _flags);
 

	
 
intptr_t rw_recvfrom(int fd,
 
                     void *bytes_ptr,
 
                     uintptr_t bytes_len,
 
                     int _flags,
 
                     const SocketAddr *peer_addr,
 
                     uintptr_t _addr_len);
 

	
 
intptr_t rw_send(int fd, const void *bytes_ptr, uintptr_t bytes_len, int _flags);
 

	
 
intptr_t rw_sendto(int fd,
 
                   void *bytes_ptr,
 
                   uintptr_t bytes_len,
 
                   int _flags,
 
                   const SocketAddr *peer_addr,
 
                   uintptr_t _addr_len);
 

	
 
int rw_socket(int _domain, int _type);
 

	
 
#endif /* REOWOLF_HEADER_DEFINED */
src/ffi/mod.rs
Show inline comments
 
use crate::{common::*, runtime::*};
 
use core::{cell::RefCell, convert::TryFrom};
 
use std::os::raw::c_int;
 
use std::slice::from_raw_parts as slice_from_raw_parts;
 

	
 
#[cfg(all(target_os = "linux", feature = "ffi_pseudo_socket_api"))]
 
/// cbindgen:ignore
 
pub mod pseudo_socket_api;
 

	
 
// Temporary simplfication: ignore ipv6. To revert, just refactor this structure and its usages
 
#[repr(C)]
 
pub struct FfiSocketAddr {
 
    pub ipv4: [u8; 4],
 
    pub port: u16,
 
}
 
impl Into<SocketAddr> for FfiSocketAddr {
 
    fn into(self) -> SocketAddr {
 
        (self.ipv4, self.port).into()
 
    }
 
}
 

	
 
///////////////////////////////////////////////
 
#[derive(Default)]
 
struct StoredError {
 
    // invariant: len is zero IFF its occupied
 
    // contents are 1+ bytes because we also store the NULL TERMINATOR
 
    buf: Vec<u8>,
 
}
 
impl StoredError {
 
    const NULL_TERMINATOR: u8 = 0;
 
    fn clear(&mut self) {
 
        // no null terminator either!
 
        self.buf.clear();
 
    }
 
    fn debug_store<E: Debug>(&mut self, error: &E) {
 
        let _ = write!(&mut self.buf, "{:?}", error);
 
        self.buf.push(Self::NULL_TERMINATOR);
 
    }
 
    fn tl_debug_store<E: Debug>(error: &E) {
 
        STORED_ERROR.with(|stored_error| {
 
            let mut stored_error = stored_error.borrow_mut();
 
            stored_error.clear();
 
            stored_error.debug_store(error);
 
        })
 
    }
 
    fn bytes_store(&mut self, bytes: &[u8]) {
 
        let _ = self.buf.write_all(bytes);
 
        self.buf.push(Self::NULL_TERMINATOR);
 
    }
 
    fn tl_bytes_store(bytes: &[u8]) {
 
        STORED_ERROR.with(|stored_error| {
 
            let mut stored_error = stored_error.borrow_mut();
 
            stored_error.clear();
 
            stored_error.bytes_store(bytes);
 
        })
 
    }
 
    fn tl_clear() {
 
        STORED_ERROR.with(|stored_error| {
 
            let mut stored_error = stored_error.borrow_mut();
 
            stored_error.clear();
 
        })
 
    }
 
    fn tl_bytes_peek() -> (*const u8, usize) {
 
        STORED_ERROR.with(|stored_error| {
 
            let stored_error = stored_error.borrow();
 
            match stored_error.buf.len() {
 
                0 => (core::ptr::null(), 0), // no error!
 
                n => {
 
                    // stores an error of length n-1 AND a NULL TERMINATOR
 
                    (stored_error.buf.as_ptr(), n - 1)
 
                }
 
            }
 
        })
 
    }
 
}
 
thread_local! {
 
    static STORED_ERROR: RefCell<StoredError> = RefCell::new(StoredError::default());
 
}
 

	
 
pub const ERR_OK: c_int = 0;
 
pub const ERR_REOWOLF: c_int = -1;
 
pub const WRONG_STATE: c_int = -2;
 
pub const LOCK_POISONED: c_int = -3;
 
pub const CLOSE_FAIL: c_int = -4;
 
pub const BAD_FD: c_int = -5;
 
pub const CONNECT_FAILED: c_int = -6;
 
pub const WOULD_BLOCK: c_int = -7;
 
pub const BAD_SOCKADDR: c_int = -8;
 
pub const SEND_BEFORE_CONNECT: c_int = -9;
 
pub const RW_OK: c_int = 0;
 
pub const RW_TL_ERR: c_int = -1;
 
pub const RW_WRONG_STATE: c_int = -2;
 
pub const RW_LOCK_POISONED: c_int = -3;
 
pub const RW_CLOSE_FAIL: c_int = -4;
 
pub const RW_BAD_FD: c_int = -5;
 
pub const RW_CONNECT_FAILED: c_int = -6;
 
pub const RW_WOULD_BLOCK: c_int = -7;
 
pub const RW_BAD_SOCKADDR: c_int = -8;
 

	
 
///////////////////// REOWOLF //////////////////////////
 

	
 
/// Returns length (via out pointer) and pointer (via return value) of the last Reowolf error.
 
/// - pointer is NULL iff there was no last error
 
/// - data at pointer is null-delimited
 
/// - len does NOT include the length of the null-delimiter
 
/// If len is NULL, it will not written to.
 
#[no_mangle]
 
pub unsafe extern "C" fn reowolf_error_peek(len: *mut usize) -> *const u8 {
 
    let (err_ptr, err_len) = StoredError::tl_bytes_peek();
 
    if !len.is_null() {
 
        len.write(err_len);
 
    }
 
    err_ptr
 
}
 

	
 
///////////////////// PROTOCOL DESCRIPTION //////////////////////////
 

	
 
/// Parses the utf8-encoded string slice to initialize a new protocol description object.
 
/// - On success, initializes `out` and returns 0
 
/// - On failure, stores an error string (see `reowolf_error_peek`) and returns -1
 
#[no_mangle]
 
pub unsafe extern "C" fn protocol_description_parse(
 
    pdl: *const u8,
 
    pdl_len: usize,
 
) -> *mut Arc<ProtocolDescription> {
 
    StoredError::tl_clear();
 
    match ProtocolDescription::parse(&*slice_from_raw_parts(pdl, pdl_len)) {
 
        Ok(new) => Box::into_raw(Box::new(Arc::new(new))),
 
        Err(err) => {
 
            StoredError::tl_bytes_store(err.as_bytes());
 
            std::ptr::null_mut()
 
        }
 
    }
 
}
 

	
 
/// Destroys the given initialized protocol description and frees its resources.
 
#[no_mangle]
 
pub unsafe extern "C" fn protocol_description_destroy(pd: *mut Arc<ProtocolDescription>) {
 
    drop(Box::from_raw(pd))
 
}
 

	
 
/// Given an initialized protocol description, initializes `out` with a clone which can be independently created or destroyed.
 
#[no_mangle]
 
pub unsafe extern "C" fn protocol_description_clone(
 
    pd: &Arc<ProtocolDescription>,
 
) -> *mut Arc<ProtocolDescription> {
 
    Box::into_raw(Box::new(pd.clone()))
 
}
 

	
 
///////////////////// CONNECTOR //////////////////////////
 

	
 
#[no_mangle]
 
pub unsafe extern "C" fn connector_new_logging(
 
    pd: &Arc<ProtocolDescription>,
 
    path_ptr: *const u8,
 
    path_len: usize,
 
) -> *mut Connector {
 
    StoredError::tl_clear();
 
    let path_bytes = &*slice_from_raw_parts(path_ptr, path_len);
 
    let path_str = match std::str::from_utf8(path_bytes) {
 
        Ok(path_str) => path_str,
 
        Err(err) => {
 
            StoredError::tl_debug_store(&err);
 
            return std::ptr::null_mut();
 
        }
 
    };
 
    match std::fs::File::create(path_str) {
 
        Ok(file) => {
 
            let connector_id = Connector::random_id();
 
            let file_logger = Box::new(FileLogger::new(connector_id, file));
 
            let c = Connector::new(file_logger, pd.clone(), connector_id);
 
            Box::into_raw(Box::new(c))
 
        }
 
        Err(err) => {
 
            StoredError::tl_debug_store(&err);
 
            std::ptr::null_mut()
 
        }
 
    }
 
}
 

	
 
#[no_mangle]
 
pub unsafe extern "C" fn connector_print_debug(connector: &mut Connector) {
 
    println!("Debug print dump {:#?}", connector);
 
}
 

	
 
/// Initializes `out` with a new connector using the given protocol description as its configuration.
 
/// The connector uses the given (internal) connector ID.
 
#[no_mangle]
 
pub unsafe extern "C" fn connector_new(pd: &Arc<ProtocolDescription>) -> *mut Connector {
 
    let c = Connector::new(Box::new(DummyLogger), pd.clone(), Connector::random_id());
 
    Box::into_raw(Box::new(c))
 
}
 

	
 
/// Destroys the given a pointer to the connector on the heap, freeing its resources.
 
/// Usable in {setup, communication} states.
 
#[no_mangle]
 
pub unsafe extern "C" fn connector_destroy(connector: *mut Connector) {
 
    drop(Box::from_raw(connector))
 
}
 

	
 
/// Given an initialized connector in setup or connecting state,
 
/// - Creates a new directed port pair with logical channel putter->getter,
 
/// - adds the ports to the native component's interface,
 
/// - and returns them using the given out pointers.
 
/// Usable in {setup, communication} states.
 
#[no_mangle]
 
pub unsafe extern "C" fn connector_add_port_pair(
 
    connector: &mut Connector,
 
    out_putter: *mut PortId,
 
    out_getter: *mut PortId,
 
) {
 
    let [o, i] = connector.new_port_pair();
 
    out_putter.write(o);
 
    out_getter.write(i);
 
}
 

	
 
/// Given
 
/// - an initialized connector in setup or connecting state,
 
/// - a string slice for the component's identifier in the connector's configured protocol description,
 
/// - a set of ports (represented as a slice; duplicates are ignored) in the native component's interface,
 
/// the connector creates a new (internal) protocol component C, such that the set of native ports are moved to C.
 
/// Usable in {setup, communication} states.
 
#[no_mangle]
 
pub unsafe extern "C" fn connector_add_component(
 
    connector: &mut Connector,
 
    ident_ptr: *const u8,
 
    ident_len: usize,
 
    ports_ptr: *const PortId,
 
    ports_len: usize,
 
) -> c_int {
 
    StoredError::tl_clear();
 
    match connector.add_component(
 
        &*slice_from_raw_parts(ident_ptr, ident_len),
 
        &*slice_from_raw_parts(ports_ptr, ports_len),
 
    ) {
 
        Ok(()) => ERR_OK,
 
        Ok(()) => RW_OK,
 
        Err(err) => {
 
            StoredError::tl_debug_store(&err);
 
            ERR_REOWOLF
 
            RW_TL_ERR
 
        }
 
    }
 
}
 

	
 
/// Given
 
/// - an initialized connector in setup or connecting state,
 
/// - a utf-8 encoded socket address,
 
/// - the logical polarity of P,
 
/// - the "physical" polarity in {Active, Passive} of the endpoint through which P's peer will be discovered,
 
/// returns P, a port newly added to the native interface.
 
#[no_mangle]
 
pub unsafe extern "C" fn connector_add_net_port(
 
    connector: &mut Connector,
 
    port: *mut PortId,
 
    addr: FfiSocketAddr,
 
    port_polarity: Polarity,
 
    endpoint_polarity: EndpointPolarity,
 
) -> c_int {
 
    StoredError::tl_clear();
 
    match connector.new_net_port(port_polarity, addr.into(), endpoint_polarity) {
 
        Ok(p) => {
 
            if !port.is_null() {
 
                port.write(p);
 
            }
 
            ERR_OK
 
            RW_OK
 
        }
 
        Err(err) => {
 
            StoredError::tl_debug_store(&err);
 
            ERR_REOWOLF
 
            RW_TL_ERR
 
        }
 
    }
 
}
 

	
 
/// Given
 
/// - an initialized connector in setup or connecting state,
 
/// - a utf-8 encoded BIND socket addresses (i.e., "local"),
 
/// - a utf-8 encoded CONNECT socket addresses (i.e., "peer"),
 
/// returns [P, G] via out pointers [putter, getter],
 
/// - where P is a Putter port that sends messages into the socket
 
/// - where G is a Getter port that recvs messages from the socket
 
#[no_mangle]
 
pub unsafe extern "C" fn connector_add_udp_mediator_component(
 
    connector: &mut Connector,
 
    putter: *mut PortId,
 
    getter: *mut PortId,
 
    local_addr: FfiSocketAddr,
 
    peer_addr: FfiSocketAddr,
 
) -> c_int {
 
    StoredError::tl_clear();
 
    match connector.new_udp_mediator_component(local_addr.into(), peer_addr.into()) {
 
        Ok([p, g]) => {
 
            if !putter.is_null() {
 
                putter.write(p);
 
            }
 
            if !getter.is_null() {
 
                getter.write(g);
 
            }
 
            ERR_OK
 
            RW_OK
 
        }
 
        Err(err) => {
 
            StoredError::tl_debug_store(&err);
 
            ERR_REOWOLF
 
            RW_TL_ERR
 
        }
 
    }
 
}
 

	
 
/// Connects this connector to the distributed system of connectors reachable through endpoints,
 
/// Usable in setup state, and changes the state to communication.
 
#[no_mangle]
 
pub unsafe extern "C" fn connector_connect(
 
    connector: &mut Connector,
 
    timeout_millis: i64,
 
) -> c_int {
 
    StoredError::tl_clear();
 
    let option_timeout_millis: Option<u64> = TryFrom::try_from(timeout_millis).ok();
 
    let timeout = option_timeout_millis.map(Duration::from_millis);
 
    match connector.connect(timeout) {
 
        Ok(()) => ERR_OK,
 
        Ok(()) => RW_OK,
 
        Err(err) => {
 
            StoredError::tl_debug_store(&err);
 
            ERR_REOWOLF
 
            RW_TL_ERR
 
        }
 
    }
 
}
 

	
 
// #[no_mangle]
 
// pub unsafe extern "C" fn connector_put_payload(
 
//     connector: &mut Connector,
 
//     port: PortId,
 
//     payload: *mut Payload,
 
// ) -> c_int {
 
//     match connector.put(port, payload.read()) {
 
//         Ok(()) => 0,
 
//         Err(err) => {
 
//             StoredError::tl_debug_store(&err);
 
//             -1
 
//         }
 
//     }
 
// }
 

	
 
// #[no_mangle]
 
// pub unsafe extern "C" fn connector_put_payload_cloning(
 
//     connector: &mut Connector,
 
//     port: PortId,
 
//     payload: &Payload,
 
// ) -> c_int {
 
//     match connector.put(port, payload.clone()) {
 
//         Ok(()) => 0,
 
//         Err(err) => {
 
//             StoredError::tl_debug_store(&err);
 
//             -1
 
//         }
 
//     }
 
// }
 

	
 
/// Convenience function combining the functionalities of
 
/// "payload_new" with "connector_put_payload".
 
#[no_mangle]
 
pub unsafe extern "C" fn connector_put_bytes(
 
    connector: &mut Connector,
 
    port: PortId,
 
    bytes_ptr: *const u8,
 
    bytes_len: usize,
 
) -> c_int {
 
    StoredError::tl_clear();
 
    let bytes = &*slice_from_raw_parts(bytes_ptr, bytes_len);
 
    match connector.put(port, Payload::from(bytes)) {
 
        Ok(()) => ERR_OK,
 
        Ok(()) => RW_OK,
 
        Err(err) => {
 
            StoredError::tl_debug_store(&err);
 
            ERR_REOWOLF
 
            RW_TL_ERR
 
        }
 
    }
 
}
 

	
 
#[no_mangle]
 
pub unsafe extern "C" fn connector_get(connector: &mut Connector, port: PortId) -> c_int {
 
    StoredError::tl_clear();
 
    match connector.get(port) {
 
        Ok(()) => ERR_OK,
 
        Ok(()) => RW_OK,
 
        Err(err) => {
 
            StoredError::tl_debug_store(&err);
 
            ERR_REOWOLF
 
            RW_TL_ERR
 
        }
 
    }
 
}
 

	
 
#[no_mangle]
 
pub unsafe extern "C" fn connector_next_batch(connector: &mut Connector) -> isize {
 
    StoredError::tl_clear();
 
    match connector.next_batch() {
 
        Ok(n) => n as isize,
 
        Err(err) => {
 
            StoredError::tl_debug_store(&err);
 
            ERR_REOWOLF as isize
 
            RW_TL_ERR as isize
 
        }
 
    }
 
}
 

	
 
#[no_mangle]
 
pub unsafe extern "C" fn connector_sync(connector: &mut Connector, timeout_millis: i64) -> isize {
 
    StoredError::tl_clear();
 
    let option_timeout_millis: Option<u64> = TryFrom::try_from(timeout_millis).ok();
 
    let timeout = option_timeout_millis.map(Duration::from_millis);
 
    match connector.sync(timeout) {
 
        Ok(n) => n as isize,
 
        Err(err) => {
 
            StoredError::tl_debug_store(&err);
 
            ERR_REOWOLF as isize
 
            RW_TL_ERR as isize
 
        }
 
    }
 
}
 

	
 
#[no_mangle]
 
pub unsafe extern "C" fn connector_gotten_bytes(
 
    connector: &mut Connector,
 
    port: PortId,
 
    out_len: *mut usize,
 
) -> *const u8 {
 
    StoredError::tl_clear();
 
    match connector.gotten(port) {
 
        Ok(payload_borrow) => {
 
            let slice = payload_borrow.as_slice();
 
            if !out_len.is_null() {
 
                out_len.write(slice.len());
 
            }
 
            slice.as_ptr()
 
        }
 
        Err(err) => {
 
            StoredError::tl_debug_store(&err);
 
            std::ptr::null()
 
        }
 
    }
 
}
 

	
 
// #[no_mangle]
 
// unsafe extern "C" fn connector_gotten_payload(
 
//     connector: &mut Connector,
 
//     port: PortId,
 
// ) -> *const Payload {
 
//     StoredError::tl_clear();
 
//     match connector.gotten(port) {
 
//         Ok(payload_borrow) => payload_borrow,
 
//         Err(err) => {
 
//             StoredError::tl_debug_store(&err);
 
//             std::ptr::null()
 
//         }
 
//     }
 
// }
 

	
 
///////////////////// PAYLOAD //////////////////////////
 
// #[no_mangle]
 
// unsafe extern "C" fn payload_new(
 
//     bytes_ptr: *const u8,
 
//     bytes_len: usize,
 
//     out_payload: *mut Payload,
 
// ) {
 
//     let bytes: &[u8] = &*slice_from_raw_parts(bytes_ptr, bytes_len);
 
//     out_payload.write(Payload::from(bytes));
 
// }
 

	
 
// #[no_mangle]
 
// unsafe extern "C" fn payload_destroy(payload: *mut Payload) {
 
//     drop(Box::from_raw(payload))
 
// }
 

	
 
// #[no_mangle]
 
// unsafe extern "C" fn payload_clone(payload: &Payload, out_payload: *mut Payload) {
 
//     out_payload.write(payload.clone())
 
// }
 

	
 
// #[no_mangle]
 
// unsafe extern "C" fn payload_peek_bytes(payload: &Payload, bytes_len: *mut usize) -> *const u8 {
 
//     let slice = payload.as_slice();
 
//     bytes_len.write(slice.len());
 
//     slice.as_ptr()
 
// }
src/ffi/pseudo_socket_api.rs
Show inline comments
 
use super::*;
 

	
 
use core::ops::DerefMut;
 
use libc::{sockaddr, socklen_t};
 
use std::{collections::HashMap, ffi::c_void, net::SocketAddr, os::raw::c_int, sync::RwLock};
 
use std::{
 
    collections::HashMap,
 
    ffi::c_void,
 
    net::SocketAddr,
 
    os::raw::c_int,
 
    sync::{Mutex, RwLock},
 
};
 
///////////////////////////////////////////////////////////////////
 

	
 
struct FdAllocator {
 
    next: Option<c_int>,
 
    freed: Vec<c_int>,
 
}
 
enum ConnectorComplexPhased {
 
    Setup { local: Option<SocketAddr>, peer: Option<SocketAddr> },
 
    Communication { putter: PortId, getter: PortId },
 
}
 
struct ConnectorComplex {
 
    // invariant: .connector.phased and .phased are variants Setup/Communication in lockstep.
 
    connector: Connector,
 
    phased: ConnectorComplexPhased,
 
}
 
#[derive(Default)]
 
struct CcMap {
 
    fd_to_cc: HashMap<c_int, Mutex<ConnectorComplex>>,
 
    fd_allocator: FdAllocator,
 
}
 
///////////////////////////////////////////////////////////////////
 
unsafe fn payload_from_raw(bytes_ptr: *const c_void, bytes_len: usize) -> Payload {
 
    let bytes_ptr = std::mem::transmute(bytes_ptr);
 
    let bytes = &*slice_from_raw_parts(bytes_ptr, bytes_len);
 
    Payload::from(bytes)
 
}
 
unsafe fn libc_to_std_sockaddr(addr: *const sockaddr, addr_len: socklen_t) -> Option<SocketAddr> {
 
    os_socketaddr::OsSocketAddr::from_raw_parts(addr as _, addr_len as usize).into_addr()
 
}
 
impl Default for FdAllocator {
 
    fn default() -> Self {
 
        // negative FDs aren't used s.t. they are available for error signalling
 
        Self { next: Some(0), 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 CC_MAP: RwLock<CcMap> = Default::default();
 
}
 
impl ConnectorComplex {
 
    fn try_become_connected(&mut self) {
 
        match self.phased {
 
            ConnectorComplexPhased::Setup { local: Some(local), peer: Some(peer) } => {
 
                // complete setup
 
                let [putter, getter] =
 
                    self.connector.new_udp_mediator_component(local, peer).unwrap();
 
                self.connector.connect(None).unwrap();
 
                self.phased = ConnectorComplexPhased::Communication { putter, getter }
 
            }
 
            _ => {} // setup incomplete
 
        }
 
    }
 
}
 
/////////////////////////////////
 
#[no_mangle]
 
pub extern "C" fn rw_socket(_domain: c_int, _type: c_int, _protocol: c_int) -> c_int {
 
    // get writer lock
 
    let mut w = if let Ok(w) = CC_MAP.write() { w } else { return LOCK_POISONED };
 
    let mut w = if let Ok(w) = CC_MAP.write() { w } else { return RW_LOCK_POISONED };
 
    let fd = w.fd_allocator.alloc();
 
    let cc = ConnectorComplex {
 
        connector: Connector::new(
 
            Box::new(crate::DummyLogger),
 
            crate::TRIVIAL_PD.clone(),
 
            Connector::random_id(),
 
        ),
 
        phased: ConnectorComplexPhased::Setup { local: None, peer: None },
 
    };
 
    w.fd_to_cc.insert(fd, Mutex::new(cc));
 
    fd
 
}
 
#[no_mangle]
 
pub extern "C" fn rw_close(fd: c_int, _how: c_int) -> c_int {
 
    // ignoring HOW
 
    // get writer lock
 
    let mut w = if let Ok(w) = CC_MAP.write() { w } else { return LOCK_POISONED };
 
    let mut w = if let Ok(w) = CC_MAP.write() { w } else { return RW_LOCK_POISONED };
 
    if w.fd_to_cc.remove(&fd).is_some() {
 
        w.fd_allocator.free(fd);
 
        ERR_OK
 
        RW_OK
 
    } else {
 
        CLOSE_FAIL
 
        RW_CLOSE_FAIL
 
    }
 
}
 
#[no_mangle]
 
pub unsafe extern "C" fn rw_bind(fd: c_int, addr: *const sockaddr, addr_len: socklen_t) -> c_int {
 
    // assuming _domain is AF_INET and _type is SOCK_DGRAM
 
    let addr = match libc_to_std_sockaddr(addr, addr_len) {
 
        Some(addr) => addr,
 
        _ => return BAD_SOCKADDR,
 
        _ => return RW_BAD_SOCKADDR,
 
    };
 
    // get outer reader, inner writer locks
 
    let r = if let Ok(r) = CC_MAP.read() { r } else { return LOCK_POISONED };
 
    let cc = if let Some(cc) = r.fd_to_cc.get(&fd) { cc } else { return BAD_FD };
 
    let mut cc = if let Ok(cc) = cc.lock() { cc } else { return LOCK_POISONED };
 
    let r = if let Ok(r) = CC_MAP.read() { r } else { return RW_LOCK_POISONED };
 
    let cc = if let Some(cc) = r.fd_to_cc.get(&fd) { cc } else { return RW_BAD_FD };
 
    let mut cc = if let Ok(cc) = cc.lock() { cc } else { return RW_LOCK_POISONED };
 
    match &mut cc.phased {
 
        ConnectorComplexPhased::Communication { .. } => WRONG_STATE,
 
        ConnectorComplexPhased::Communication { .. } => RW_WRONG_STATE,
 
        ConnectorComplexPhased::Setup { local, .. } => {
 
            *local = Some(addr);
 
            cc.try_become_connected();
 
            ERR_OK
 
            RW_OK
 
        }
 
    }
 
}
 
#[no_mangle]
 
pub unsafe extern "C" fn rw_connect(
 
    fd: c_int,
 
    addr: *const sockaddr,
 
    addr_len: socklen_t,
 
) -> c_int {
 
    let addr = match libc_to_std_sockaddr(addr, addr_len) {
 
        Some(addr) => addr,
 
        _ => return BAD_SOCKADDR,
 
        _ => return RW_BAD_SOCKADDR,
 
    };
 
    // assuming _domain is AF_INET and _type is SOCK_DGRAM
 
    // get outer reader, inner writer locks
 
    let r = if let Ok(r) = CC_MAP.read() { r } else { return LOCK_POISONED };
 
    let cc = if let Some(cc) = r.fd_to_cc.get(&fd) { cc } else { return BAD_FD };
 
    let mut cc = if let Ok(cc) = cc.lock() { cc } else { return LOCK_POISONED };
 
    let r = if let Ok(r) = CC_MAP.read() { r } else { return RW_LOCK_POISONED };
 
    let cc = if let Some(cc) = r.fd_to_cc.get(&fd) { cc } else { return RW_BAD_FD };
 
    let mut cc = if let Ok(cc) = cc.lock() { cc } else { return RW_LOCK_POISONED };
 
    match &mut cc.phased {
 
        ConnectorComplexPhased::Communication { .. } => WRONG_STATE,
 
        ConnectorComplexPhased::Communication { .. } => RW_WRONG_STATE,
 
        ConnectorComplexPhased::Setup { peer, .. } => {
 
            *peer = Some(addr);
 
            cc.try_become_connected();
 
            ERR_OK
 
            RW_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 {
 
    // ignoring flags
 
    // get outer reader, inner writer locks
 
    let r = if let Ok(r) = CC_MAP.read() { r } else { return LOCK_POISONED as isize };
 
    let cc = if let Some(cc) = r.fd_to_cc.get(&fd) { cc } else { return BAD_FD as isize };
 
    let mut cc = if let Ok(cc) = cc.lock() { cc } else { return LOCK_POISONED as isize };
 
    let r = if let Ok(r) = CC_MAP.read() { r } else { return RW_LOCK_POISONED as isize };
 
    let cc = if let Some(cc) = r.fd_to_cc.get(&fd) { cc } else { return RW_BAD_FD as isize };
 
    let mut cc = if let Ok(cc) = cc.lock() { cc } else { return RW_LOCK_POISONED as isize };
 
    let ConnectorComplex { connector, phased } = cc.deref_mut();
 
    match phased {
 
        ConnectorComplexPhased::Setup { .. } => WRONG_STATE as isize,
 
        ConnectorComplexPhased::Setup { .. } => RW_WRONG_STATE as isize,
 
        ConnectorComplexPhased::Communication { putter, .. } => {
 
            let payload = payload_from_raw(bytes_ptr, bytes_len);
 
            connector.put(*putter, payload).unwrap();
 
            connector.sync(None).unwrap();
 
            bytes_len as isize
 
        }
 
    }
 
}
 
#[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
 
    // get outer reader, inner writer locks
 
    let r = if let Ok(r) = CC_MAP.read() { r } else { return LOCK_POISONED as isize };
 
    let cc = if let Some(cc) = r.fd_to_cc.get(&fd) { cc } else { return BAD_FD as isize };
 
    let mut cc = if let Ok(cc) = cc.lock() { cc } else { return LOCK_POISONED as isize };
 
    let r = if let Ok(r) = CC_MAP.read() { r } else { return RW_LOCK_POISONED as isize };
 
    let cc = if let Some(cc) = r.fd_to_cc.get(&fd) { cc } else { return RW_BAD_FD as isize };
 
    let mut cc = if let Ok(cc) = cc.lock() { cc } else { return RW_LOCK_POISONED as isize };
 
    let ConnectorComplex { connector, phased } = cc.deref_mut();
 
    match phased {
 
        ConnectorComplexPhased::Setup { .. } => WRONG_STATE as isize,
 
        ConnectorComplexPhased::Setup { .. } => RW_WRONG_STATE as isize,
 
        ConnectorComplexPhased::Communication { getter, .. } => {
 
            connector.get(*getter).unwrap();
 
            connector.sync(None).unwrap();
 
            let slice = connector.gotten(*getter).unwrap().as_slice();
 
            if !bytes_ptr.is_null() {
 
                let cpy_msg_bytes = slice.len().min(bytes_len);
 
                std::ptr::copy_nonoverlapping(slice.as_ptr(), bytes_ptr as *mut u8, cpy_msg_bytes);
 
            }
 
            slice.len() as isize
 
        }
 
    }
 
}
0 comments (0 inline, 0 general)