libskabus
skabus
Software
skarnet.org

The skabus/rpc.h library interface

The skabus_rpc library provides an API for clients to the skabus-rpcd daemon. This is the way they register interfaces and send queries to other clients.

Programming

Check the skabus/rpc.h header for details of the data types and function prototypes.

Overview, data types, interface callbacks

A client starts by defining a skabus_rpc_t handle, initializing it to SKABUS_RPC_ZERO. It then passes a pointer to this handle in all its subsequent skabus_rpc calls, starting with skabus_rpc_init() and ending with skabus_rpc_end().

At initialization time, as well as interface registration time, the client must provide a pointer to a skabus_rpc_interface_t structure. This structure contains the following fields:

f is the callback function that will be called when the interface receives a query. Its prototype is int f (skabus_rpc_t *a, skabus_rpc_rinfo_t const *info, unixmessage_t const *m, void *aux).

cancelf is the callback function that will be called if the qclient, or skabus-rpcd, cancels a query made to the interface. Its prototype is int cancelf (uint64_t serial, char reason, void *aux).

data is an arbitrary pointer chosen by the rclient to point to arbitrary data, for whatever purpose the rclient may see fit. This pointer will be given as the aux argument to the f or cancelf callbacks when they're called.

Starting and ending a session

int skabus_rpc_init (skabus_rpc_t *a, char const *path, char const *id, skabus_rpc_interface_t const *ifbody, char const *re, tain_t const *deadline, tain_t *stamp)

Starts a session with an instance of skabus-rpcd listening on the socket at path. The client attempts to register the id identifier for itself, and will reply to private queries (queries directly sent to it, instead of to an interface) with the functions defined in ifbody. Only qclients whose identifiers match the re regular expression will be able to send private queries.

If no private queries are to be served, &skabus_rpc_interface_zero can be used as an ifbody argument; and a never-matching regular expression, such as .^, should be used as a re argument.

The client must be authorized to use id as an identifier. That means id must match the regular expression given as an env/SKABUS_RPC_ID_REGEX entry for the client's uid or gid in the skabus-rpcd configuration.

On success, the function returns nonzero. The a handle then needs to be used as the first argument to all the subsequent skabus_rpc function calls. On failure, the function returns 0, and sets errno.

void skabus_rpc_end (skabus_rpc_t *a)

Ends the current session with handle a.

Registering and unregistering an interface

int skabus_rpc_interface_register (skabus_rpc_t *a, uint32_t *ifid, char const *ifname, skabus_rpc_interface_t const *ifbody, char const *re, tain_t const *deadline, tain_t *stamp)

Registers an interface with name ifname and implementation pointed to by ifbody. qclients wanting to send queries to ifname will need to have an identifier matching the re regular expression.

The rclient must be authorized to use ifname as an interface name. That means ifname must match the regular expression given as an env/SKABUS_RPC_INTERFACES_REGEX entry for the rclient's uid or gid in the skabus-rpcd configuration.

On success, the function stores an interface identifier into ifid, and returns nonzero. On failure, it returns 0, and sets errno.

int skabus_rpc_interface_unregister (skabus_rpc_t *a, uint32_t ifid, tain_t const *deadline, tain_t *stamp)

Unregisters the interface with id ifid. ifid may be reused in future interface registrations.

The application should ensure it is not currently handling queries to that interface before calling this function. All the pending queries (i.e. sent, but not yet read by the rclient) to that interface will fail will the ECONNRESET reason.

On success, the function returns nonzero. On failure, it returns 0, and sets errno.

Sending and cancelling a query

uint64_t skabus_rpc_send_withfds (skabus_rpc_t *a, char const *ifname, char const *s, size_t len, int const *fds, unsigned int nfds, unsigned char const *bits, tain_t const *limit, tain_t const *deadline, tain_t *stamp)

Sends a query to interface ifname. The query is made of len bytes of data pointed to by s, as well as nfds open file descriptors whose list is pointed to by fds.

If nfds is nonzero, the qclient must be authorized to send descriptors. That means the ruleset that matched the qclient at connection time must contain a nonempty env/SKABUS_RPC_QSENDFDS entry.

bits is a bitfield containing at least nfds bits. If the nth bit is 1, it means that fds[n] will be closed after being sent to skabus-rpcd. If it is 0, the fd will not be touched. As a bits value, you can use unixmessage_bits_closenone to close nothing, or unixmessage_bits_closeall to close all the descriptors in fds.

limit is an absolute date at which the query will fail with the ETIMEDOUT reason if the answer hasn't arrived by then. This deadline will be enforced by the server and also transmitted to the rclient for information.

Please note that limit refers to an actual deadline for the whole lifetime of the query, i.e. transmission to the rclient, handling by the rclient, and transmission of the reply to the qclient. This has nothing to do with the deadline argument, which is a deadline for the current skabus_rpc_send_withfds() function call. If limit is reached, it's normal operation - the query simply took too long to be handled. But if deadline (which should be way earlier than limit) is reached, it means the server got stuck somewhere in the initial function call, and it's not normal operation at all.

On success, the function returns a 64-bit value that is the serial number of the query. On failure, it returns 0, and sets errno.

uint64_t skabus_rpc_send(skabus_rpc_t *a, char const *ifname, char const *s, size_t len, tain_t const *limit, tain_t const *deadline, tain_t *stamp)

Sends a text-only query to ifname. It's a wrapper over skabus_rpc_send_withfds.

uint64_t skabus_rpc_sendv_withfds (skabus_rpc_t *a, char const *ifname, struct iovec const *v, unsigned int vlen, int const *fds, unsigned int nfds, unsigned char const *bits, tain_t const *limit, tain_t const *deadline, tain_t *stamp)

Like skabus_rpc_send_withfds, except the text of the query is not given as a single array of bytes, but as several chunks of data defined by the v array of length vlen.

uint64_t skabus_rpc_sendv(skabus_rpc_t *a, char const *ifname, struct iovec const *v, unsigned int vlen, tain_t const *limit, tain_t const *deadline, tain_t *stamp)

Like skabus_rpc_send, except the text of the query is not given as a single array of bytes, but as several chunks of data defined by the v array of length vlen.

uint64_t skabus_rpc_sendpm_withfds (skabus_rpc_t *a, char const *rid, char const *s, size_t len, int const *fds, unsigned int nfds, unsigned char const *bits, tain_t const *limit, tain_t const *deadline, tain_t *stamp)
uint64_t skabus_rpc_sendpm (skabus_rpc_t *a, char const *rid, char const *s, size_t len, tain_t const *limit, tain_t const *deadline, tain_t *stamp)
uint64_t skabus_rpc_sendvpm_withfds (skabus_rpc_t *a, char const *rid, struct iovec const *v, unsigned int vlen, int const *fds, unsigned int nfds, unsigned char const *bits, tain_t const *limit, tain_t const *deadline, tain_t *stamp)
uint64_t skabus_rpc_sendvpm (skabus_rpc_t *a, char const *rid, struct iovec const *v, unsigned int vlen, tain_t const *limit, tain_t const *deadline, tain_t *stamp)

These functions are the equivalent of the previous ones, but send a private query instead. rid is not an interface name, but a client identifier. If accepted, the query will be handled by the interface body that has been declared by the rid client when it registered itself.

int skabus_rpc_cancel (skabus_rpc_t *a, uint64_t serial, tain_t const *deadline, tain_t *stamp)

Cancels the query numbered serial. If the query is currently being handled by the rclient, the rclient will be notified (the appropriate cancelf callback will be called).

On success, the function returns nonzero. On failure, it returns 0, and sets errno.

Answering queries

One of these functions must be called in every f callback defined in interface bodies, in order to send the reply to the qclient.

int skabus_rpc_reply_withfds (skabus_rpc_t *a, uint64_t serial, char result, char const *s, size_t len, int const *fds, unsigned int nfds, unsigned char const *bits, tain_t const *deadline, tain_t *stamp)

Sends a reply to the query numbered serial. This reply is made of an overall value result (it is suggested to use 0 to mean "the query was handled properly, even if it returns a negative answer", and an errno code to mean "the query could not be handled properly by the rclient"), as well as a message containing len bytes pointed by s and potentially nfds open file descriptors pointed to by fds.

If nfds is nonzero, the rclient must be authorized to send descriptors. That means the ruleset that matched the rclient at connection time must contain a nonempty env/SKABUS_RPC_RSENDFDS entry.

bits is a bitfield containing at least nfds bits. If the nth bit is 1, it means that fds[n] will be closed after being sent to skabus-rpcd. If it is 0, the fd will not be touched. As a bits value, you can use unixmessage_bits_closenone to close nothing, or unixmessage_bits_closeall to close all the descriptors in fds.

The function returns nonzero if it could send the reply to skabus-rpcd. If it could not, it returns 0 and sets errno. Note that the function will still return nonzero if serial does not match a query that was sent to this rclient; in that case, skabus-rpcd will silently ignore the reply.

int skabus_rpc_reply (skabus_rpc_t *a, uint64_t serial, char result, char const *s, size_t len, tain_t const *deadline, tain_t *stamp)

Shortcut for skabus_rpc_reply_withfds when the reply does not contain any file descriptors.

int skabus_rpc_replyv_withfds (skabus_rpc_t *a, uint64_t serial, char result, struct iovec const *v, unsigned int vlen, int const *fds, unsigned int nfds, unsigned char const *bits, tain_t const *deadline, tain_t *stamp)

Similar to skabus_rpc_reply_withfds, but the text of the reply is made of vlen chunks described in the v array.

int skabus_rpc_replyv (skabus_rpc_t *a, uint64_t serial, char result, struct iovec const *s, unsigned int vlen, tain_t const *deadline, tain_t *stamp)

Shortcut for skabus_rpc_replyv_withfds when the reply does not contain any file descriptors.

Getting replies to queries

int skabus_rpc_fd (skabus_rpc_t *a)

Returns a file descriptor for the connection to skabus-rpcd. This file descriptor can be checked for reading in an asynchronous event loop with a poll or select call. (For easy timeout management, iopause is recommended.) When the descriptor is readable, do not read it, but call the following function instead.

int skabus_rpc_update (skabus_rpc_t *a)

Updates the qclient's data structures with the latest information from skabus-rpcd. This function should be called when the connection descriptor becomes readable.

The function returns a negative number (and sets errno) if an error occurs, 0 if nothing happened, and a positive number if new answers have arrived.

size_t skabus_rpc_qlist (skabus_rpc_t *a, uint64_t **list)

Returns the number of currently unaddressed answers. If that number is greater than 0, a pointer to an array containing the list of unaddressed answers is stored into *list. The elements of the array are the serial numbers for the queries whose answered have arrived.

The *list pointer is only valid until the next invocation of skabus_rpc_update().

int skabus_rpc_get (skabus_rpc_t *a, uint64_t serial, int *result, unixmessage_t *m)

Get the answer for the query numbered serial. Returns a negative number (and sets errno) if an error occurred. errno is EINVAL if serial is an invalid query number. Returns 0 if no answer has arrived yet. Returns a positive number if the reply has arrived, in which case the overall result value is stored into *result, and the reply message is pointed by m.

m points to a unixmessage_t structure containing the following fields:

If the reply is unwanted, the qclient should call unixmessage_drop(m) to make sure all file descriptors contained in it, if any, are closed.

int skabus_rpc_release (skabus_rpc_t *a, uint64_t serial)

Releases the resources occupied by the reply to the query numbered serial. Only call this function when the reply has been handled, or at least when the message text, and file descriptors if any, have been copied to another place.

The function returns 1 on success, and 0 (and sets errno) on failure. errno is EINVAL if serial is an invalid number, and EAGAIN if the query is in-flight. To cancel an in-flight query, use skabus_rpc_cancel instead.

void skabus_rpc_qlist_ack (skabus_rpc_t *a, size_t n)

Acknowledges that n replies have been handled: removes n elements at the head of the queue that skabus_rpc_qlist returns.