/** * @brief Fibre C library * * The library is fully asynchronous and runs on an application-managed event * loop. This integration happens with the call to libfibre_open(), where the * application must pass a couple of functions that libfibre will use to put * tasks on the event loop. * * Some general things to note: * - None of the library's functions are blocking. * - None of the library's functions can be expected to be thread-safe, they * should not be invoked from any other thread than the one that runs the * event loop. * - Callbacks that the user passes to a libfibre function are always executed * on the event loop thread. * - All of the library's functions can be expected reentry-safe. That means * you can call into any libfibre function from any callback handler that * libfibre invokes. */ #ifndef __LIBFIBRE_H #define __LIBFIBRE_H #include #include #if defined(_MSC_VER) # define DLL_EXPORT __declspec(dllexport) # define DLL_IMPORT __declspec(dllimport) #elif defined(__GNUC__) # define DLL_EXPORT __attribute__((visibility("default"))) # define DLL_IMPORT # if __GNUC__ > 4 # define DLL_LOCAL __attribute__((visibility("hidden"))) # else # define DLL_LOCAL # endif #else # error("Don't know how to export shared object libraries") #endif #ifdef FIBRE_COMPILE # ifndef FIBRE_PUBLIC # define FIBRE_PUBLIC DLL_EXPORT # endif # define FIBRE_PRIVATE DLL_LOCAL #else # define FIBRE_PUBLIC DLL_IMPORT #endif #define FIBRE_PRIVATE DLL_LOCAL #ifdef __cplusplus extern "C" { #endif struct LibFibreCtx; struct LibFibreDiscoveryCtx; struct LibFibreCallContext; struct LibFibreObject; struct LibFibreInterface; struct LibFibreFunction; struct LibFibreAttribute; struct LibFibreTxStream; struct LibFibreRxStream; struct LibFibreDomain; // This enum must remain identical to fibre::Status. enum LibFibreStatus { kFibreOk, kFibreBusy, // libfibre * Client Application <==== (tx_end, rx_end, status) ===== libfibre * * These tuples are exchanged through the input/output arguments of * libfibre_call() or libfibre_call()'s callback. * * If during an ongoing call either of the two parties is unable to respond * immediately it responds with kFibreBusy and will thus get the responsibility * to resume the call when able. kFibreCancelled can be issued by either party * at any time. * * Each party must make progress during every control transfer to the other * party. * * For the application this means for every call to libfibre_call() and every * return from libfibre_call()'s callback the arguments passed from application * to libfibre must satisfy at least one of the following: * * - The call handle is NULL * - tx_len is non-zero * - rx_len is non-zero * - The status is different from kFibreOk * * For libfibre this means every for return from libfibre_call() and every * call to libfibre_call()'s callback the arguments passed from libfibre to * application satisfy at least one of the following: * * - tx_end is larger than the corresponding tx_buf * - rx_end is larger than the corresponding rx_buf * - The status is different from kFibreOk * * @param func: A function handle that was obtained in the on_function_added() * callback of libfibre_subscribe_to_interface(). * @param handle: The variable being pointed to by this argument identifies the * coroutine call. If the variable is NULL it will be set to a new opaque * handle. If the variable is not NULL the active function call is * continued or cancelled (depending on status). * @param tx_buf: The buffer to transmit. If libfibre_call() returns kFibreBusy * then this buffer must remain valid until `callback` is invoked. * Otherwise it can be freed immediately after this call. * @param tx_len: Length of tx_buf. Must be zero if tx_buf is NULL. * @param rx_buf: The buffer into which the received data should be written. If * libfibre_call() returns kFibreBusy then this buffer must remain * allocated until `callback` is invoked. Otherwise it can be freed * immediately after this call. * @param rx_len: Length of rx_buf. Must be zero if rx_buf is NULL. * @param tx_end: End of the range of data that was accepted by libfibre. This * is always in the interval [tx_buf, tx_buf + tx_len] unless * libfibre_call() returns kFibreBusy, in which case this is NULL. * This value does not give any delivery guarantees. * @param rx_end: End of the range of data that was returned by libfibre. This * is always in the interval [rx_buf, rx_buf + rx_len] unless * libfibre_call() returns kFibreBusy, in which case this is NULL. * @param callback: Will be invoked eventually if and only if libfibre_call() * returns kFibreBusy. This callback is never invoked from inside * libfibre_call(). * @param cb_ctx: An opaque application-defined handle that gets passed to * `callback`. * * @retval kFibreOk: libfibre accepted some or all of the tx_buf or filled some * or all of the rx_buf with data and can immediately accept more TX * data or provide more RX data. * @retval kFibreBusy: libfibre will complete the request asynchronously by * calling `callback`. If this value is returned, then the application * must not invoke libfibre_call() on the same call handle again until * `callback` is invoked except for cancelling the call with a status * of `kFibreCancelled`. * @retval kFibreClosed: the remote server completed the call and will not * accept or return any more data on this call. The application must not * pass the closed call context handle to libfibre_call() anymore. * @retval kFibreCancelled: the application's cancellation request was honored * or the remote server cancelled the call. The application must not * pass the cancelled call context handle to libfibre_call() anymore. */ FIBRE_PUBLIC LibFibreStatus libfibre_call(LibFibreFunction* func, LibFibreCallContext** handle, LibFibreStatus status, const unsigned char* tx_buf, size_t tx_len, unsigned char* rx_buf, size_t rx_len, const unsigned char** tx_end, unsigned char** rx_end, libfibre_call_cb_t callback, void* cb_ctx); /** * @brief Starts sending data on the specified TX stream. * * The TX operation must be considered in progress until the on_completed * callback is called. Until then the application must not start another TX * operation on the same stream. In the meantime the application can call * libfibre_cancel_tx() at any time to abort the operation. * * @param tx_stream: The stream on which to send data. * @param tx_buf: The buffer to transmit. Must remain valid until the operation * completes. * @param tx_len: Length of tx_buf. * @param on_completed: Called when the operation completes, whether successful * or not. * @param ctx: Arbitrary user data passed to the on_completed callback. */ FIBRE_PUBLIC void libfibre_start_tx(LibFibreTxStream* tx_stream, const uint8_t* tx_buf, size_t tx_len, on_tx_completed_cb_t on_completed, void* ctx); /** * @brief Cancels an ongoing TX operation. * * Must only be called if there is actually a TX operation in progress for which * cancellation has not yet been requested. * The application must still wait for the on_complete callback to be called * before the operation can be considered finished. The completion callback may * be called with kFibreCancelled or any other status. * * TODO: specify if streams can be restarted (current doc of on_tx_completed_cb_t implies no) * * @param tx_stream: The TX stream on which to cancel the ongoing TX operation. */ FIBRE_PUBLIC void libfibre_cancel_tx(LibFibreTxStream* tx_stream); /** * @brief Permanently close TX stream. * * Must not be called while a transfer is ongoing. */ FIBRE_PUBLIC void libfibre_close_tx(LibFibreTxStream* tx_stream, LibFibreStatus status); /** * @brief Starts receiving data on the specified RX stream. * * The RX operation must be considered in progress until the on_completed * callback is called. Until then the application must not start another RX * operation on the same stream. In the meantime the application can call * libfibre_cancel_rx() at any time to abort the operation. * * @param rx_stream: The stream on which to receive data. * @param rx_buf: The buffer to receive to. Must remain valid until the * operation completes. * @param rx_len: Length of rx_buf. * @param on_completed: Called when the operation completes, whether successful * or not. * @param ctx: Arbitrary user data passed to the on_completed callback. */ FIBRE_PUBLIC void libfibre_start_rx(LibFibreRxStream* rx_stream, uint8_t* rx_buf, size_t rx_len, on_rx_completed_cb_t on_completed, void* ctx); /** * @brief Cancels an ongoing RX operation. * * Must only be called if there is actually a RX operation in progress for which * cancellation has not yet been requested. * The application must still wait for the on_complete callback to be called * before the operation can be considered finished. The completion callback may * be called with kFibreCancelled or any other status. * * TODO: specify if streams can be restarted (current doc of on_rx_completed_cb_t implies no) * * @param rx_stream: The RX stream on which to cancel the ongoing RX operation. */ FIBRE_PUBLIC void libfibre_cancel_rx(LibFibreRxStream* rx_stream); /** * @brief Permanently close RX stream. * * Must not be called while a transfer is ongoing. */ FIBRE_PUBLIC void libfibre_close_rx(LibFibreRxStream* rx_stream, LibFibreStatus status); #ifdef __cplusplus } #endif #endif // __LIBFIBRE_H