115 lines
6.1 KiB

#ifndef LIBIPC
#define LIBIPC
#include <stdint.h>
The LibIPC API is designed to be simple.
For most applications, the usage can be summarized as:
- ipc_context_init to allocate the "context" structure;
- ipc_service_init or ipc_connect_service to instanciate the service or starts a connection to it;
- loop over ipc_wait_event to wait for events;
- ipc_schedule to send messages;
- ipc_close_all then ipc_context_deinit to close all connections then free the context.
The ipc_wait_event function is where the magic happens.
This function handles all the complexity of network management, juggling with file descriptors,
storing connection-related data, waiting for an event, handling connections and disconnections,
reading incoming messages and providing UNDERSTANDABLE notifications (see the `event_types` enumeration).
Basic events are:
- Connections and disconnections, they are already handled within LibIPC, but the API notifies the
user so they can perform additional operations;
- Messages (received or sent);
- Timers, to wake up the application on a regular basis (setup with ipc_context_timer).
Furthermore, the API can be used for non-IPC communications, meaning connections not using the LibIPC protocol.
This is particularly useful when dealing with any file descriptor that needs attention.
The ipc_add_external function adds a file descriptor marked as "external" which will be listened on by LibIPC.
In this case, disconnections are still handled, but messages aren't automatically read.
This way, almost any protocol can be used along with LibIPC communications and with the LibIPC API.
Related event: EXTERNAL, notifying users that an "external" file descriptor received a message.
Finally, a "switch" mechanism to automatically transfer messages between a pair of file descriptors (ipc_add_switch).
Messages are automatically exchanged between the two file descriptors by LibIPC;
eventually with user-provided callbacks (ipc_set_switch_callbacks) for non-IPC connections.
Thus, callbacks enable to handle websocket connections, non-IPC clients communicating with JSON messages, etc.
Related events: SWITCH RX and TX, notifying users that a "switched" file descriptor received (or sent) a message.
Switch and IO callbacks enable to easily create "protocol IPC services" (such as TCPd) to
bind IPC services to basically any available protocol through small, dedicated services
handling all the nitty-gritty details of non-IPC protocols.
// Event types: the "t" parameter in "ipc_wait_event".
enum event_types {
ERROR = 0 // A problem occured.
, CONNECTION = 1 // New user.
, DISCONNECTION = 2 // User disconnected.
, MESSAGE_RX = 3 // New message.
, MESSAGE_TX = 4 // Message sent.
, TIMER = 5 // Timeout in the poll(2) function.
, EXTERNAL = 6 // Message received from a non-IPC socket.
, SWITCH_RX = 7 // Message received from a switched fd.
, SWITCH_TX = 8 // Message sent to a switched fd.
// Return type of callback functions when switching.
enum cb_event_types {
CB_NO_ERROR = 0 // No error. A message was generated.
, CB_ERROR = 1 // Generic error.
, CB_FD_CLOSING = 2 // The fd is closing.
, CB_IGNORE = 3 // The message should be ignored (protocol specific).
int ipc_context_init (void** ptr); // Allocate memory for a context.
void ipc_context_deinit (void** ctx); // Free the context's memory.
void ipc_context_timer (void* ctx, int timer); // Change the timer (for timer events, in ms).
// Init (or connect to) a service. That's almost the same operation behind the scene.
int ipc_service_init (void* ctx, int* servicefd, const char* service_name, uint16_t service_name_len);
int ipc_connect_service (void* ctx, int* servicefd, const char* service_name, uint16_t service_name_len);
// Write a message or schedule it.
int ipc_write (void* ctx, int servicefd, const char* mcontent, size_t mlen);
int ipc_schedule (void* ctx, int servicefd, const char* mcontent, size_t mlen);
// Read a message from a client; either selected by an index in the context structure or by its file descriptor.
int ipc_read_fd (void* ctx, int fd, char* buffer, size_t* buflen);
int ipc_read (void* ctx, size_t index, char* buffer, size_t* buflen);
// Wait for an event.
// The "t" parameter is the type of the event (enum event_types).
// The "index" parameter is the index in the context structure of the origin of the event (client or server).
// The "originfd" parameter is the file descriptor on which the event occurs.
// The "newfd" parameter is the file descriptor of the new connected client, in case of a connection event.
// The "buffer" and "buflen" parameters contain respectively a copy of the received message and its length.
int ipc_wait_event (void* ctx, char* t, size_t* index, int* originfd, int* newfd, char* buffer, size_t* buflen);
// Close a client (or server) based on its file descriptor or its index in the context structure.
int ipc_close_fd (void* ctx, int fd);
int ipc_close (void* ctx, size_t index);
// Close all connections (probably right before the processus is terminated).
int ipc_close_all (void* ctx);
// Add a (possibly non-IPC) file descriptor to handle.
// Since it's not marked as an IPC connection, messages won't be automatically read;
// which enables to handle any communications for most protocols through the LibIPC API.
int ipc_add_external (void* ctx, int newfd);
// Add a new switch between a pair of file descriptors, enabling automatic exchange of messages
// between this pair of fds. Useful for "protocol services", such as TCPd.
int ipc_add_switch (void* ctx, int fd1, int fd2);
// Set IO callbacks for a file descriptor.
// Returned "char" is a cb_event_types enum.
// One of the callbacks can be "NULL" to keep the default callback, thus changing only input or output operations.
int ipc_set_switch_callbacks (void* ctx, int fd
, char (*in (int orig, char *payload, size_t *mlen))
, char (*out(int dest, const char *payload, size_t mlen)));