NAME
imsg_add
,
imsg_close
, imsg_compose
,
imsg_compose_ibuf
,
imsg_composev
, imsg_create
,
imsg_forward
, imsg_free
,
imsg_get
, imsg_get_data
,
imsg_get_fd
, imsg_get_ibuf
,
imsg_get_id
, imsg_get_ibuf
,
imsg_get_len
, imsg_get_pid
,
imsg_get_type
,
imsgbuf_allow_fdpass
,
imsgbuf_clear
,
imsgbuf_flush
, imsgbuf_init
,
imsgbuf_queuelen
,
imsgbuf_read
,
imsgbuf_set_maxsize
,
imsgbuf_write
—
IPC messaging functions
SYNOPSIS
#include
<sys/queue.h>
#include <imsg.h>
#define IMSG_HEADER_SIZE sizeof(struct
imsg_hdr)
#define MAX_IMSGSIZE 16384
int
imsg_add
(struct
ibuf *msg, const void
*data, size_t
datalen);
void
imsg_close
(struct
imsgbuf *imsgbuf, struct
ibuf *msg);
int
imsg_compose
(struct
imsgbuf *imsgbuf,
uint32_t type,
uint32_t id,
pid_t pid,
int fd,
const void *data,
size_t datalen);
int
imsg_compose_ibuf
(struct
imsgbuf *imsgbuf,
uint32_t type,
uint32_t id,
pid_t pid,
struct ibuf *buf);
struct ibuf *
imsg_create
(struct
imsgbuf *imsgbuf,
uint32_t type,
uint32_t id,
pid_t pid,
size_t datalen);
int
imsg_forward
(struct
imsgbuf *imsgbuf, struct
imsg *msg);
void
imsg_free
(struct
imsg *imsg);
ssize_t
imsg_get
(struct
imsgbuf *imsgbuf, struct
imsg *imsg);
int
imsg_get_data
(struct
imsg *imsg, void
*data, size_t
len);
int
imsg_get_fd
(struct
imsg *imsg);
int
imsg_get_ibuf
(struct
imsg *imsg, struct ibuf
*ibuf);
uint32_t
imsg_get_id
(struct
imsg *imsg);
size_t
imsg_get_len
(struct
imsg *imsg);
pid_t
imsg_get_pid
(struct
imsg *imsg);
uint32_t
imsg_get_type
(struct
imsg *imsg);
void
imsgbuf_allow_fdpass
(struct
imsgbuf *imsgbuf);
void
imsgbuf_clear
(struct
imsgbuf *imsgbuf);
int
imsgbuf_flush
(struct
imsgbuf *imsgbuf);
int
imsgbuf_init
(struct
imsgbuf *imsgbuf, int
fd);
uint32_t
imsgbuf_queuelen
(struct
imsgbuf *imsgbuf);
int
imsgbuf_read
(struct
imsgbuf *imsgbuf);
int
imsgbuf_set_maxsize
(struct
imsgbuf *imsgbuf,
uint32_t maxsize);
int
imsgbuf_write
(struct
imsgbuf *imsgbuf);
#include
<sys/uio.h>
int
imsg_composev
(struct
imsgbuf *imsgbuf,
uint32_t type,
uint32_t id,
pid_t pid,
int fd,
const struct iovec *iov,
int iovcnt);
DESCRIPTION
The imsg
functions provide a simple
mechanism for communication between local processes using sockets. Each
transmitted message is guaranteed to be presented to the receiving program
whole. They are commonly used in privilege separated processes, where
processes with different rights are required to cooperate.
A program using these functions should be linked with -lutil.
imsgbuf_init
()
initializes imsgbuf as one side of a channel
associated with fd. The file descriptor is used to
send and receive messages, but is not closed by any of the imsg functions.
It returns 0 if successful and -1 on failure.
imsgbuf_allow_fdpass
()
enables file descriptor passing in both directions for this
imsgbuf.
imsgbuf_set_maxsize
()
changes the default maximum imsg size from
MAX_IMSGSIZE
to maxsize.
maxsize must be bigger than
IMSG_HEADER_SIZE
. It returns 0 if successful and -1
on failure.
The
imsgbuf_clear
()
function frees any data allocated as part of an imsgbuf. This function does
not close the file descriptor used for communication.
The
imsgbuf_read
()
routine reads pending data with
recvmsg(2) and queues it as individual messages on
imsgbuf. It returns 1 on success, 0 if the connection
is closed, or -1 on error and the global variable
errno is set to indicate the error. The errors
EINTR
and EAGAIN
are treated
as follows. EINTR
will automatically retry the read
operation while the other errors are ignored with a 1 return.
imsgbuf_write
()
writes out queued messages. It returns 0 if it succeeds, -1 on error and the
global variable errno is set to indicate the error.
The errors EINTR
, EAGAIN
,
and ENOBUFS
are treated as follows.
EINTR
will automatically retry the write operation
while the other errors are ignored with a 0 return.
imsgbuf_flush
()
calls imsgbuf_write
() in a loop until all imsgs in
the output buffer are sent. It returns 0 if it succeeds, -1 otherwise and
the global variable errno is set to indicate the
error. imsgbuf_flush
() should not be called on
non-blocking sockets since it will busy loop if the socket is not
available.
imsgbuf_queuelen
()
returns the number of messages ready to be sent. This function returns 0 if
no messages are pending for transmission.
imsg_create
(),
imsg_add
() and imsg_close
()
are generic construction routines for messages that are to be sent using an
imsgbuf.
imsg_create
()
creates a new message with header specified by type,
id and pid. A
pid of zero uses the process ID returned by
getpid(2)
when imsgbuf was initialized. In addition to this
common imsg header, datalen bytes of space may be
reserved for attaching to this imsg. This space is populated using
imsg_add
(). imsg_create
()
returns a pointer to a new message if it succeeds, NULL otherwise.
imsg_add
()
appends to msg datalen bytes of
ancillary data pointed to by data. It returns
datalen if it succeeds, otherwise
msg is freed and -1 is returned.
imsg_close
()
completes creation of msg by adding it to
imsgbuf output buffer.
imsg_compose
()
is used to quickly create and queue an imsg. It takes the same parameters as
the imsg_create
(),
imsg_add
() and imsg_close
()
routines, except that only one ancillary data buffer can be provided.
Additionally, the file descriptor fd may be passed
over the socket to the other process. If fd is given,
it is closed in the sending program after the message is sent. A value of -1
indicates no file descriptor should be passed. This routine returns 1 if it
succeeds, -1 otherwise.
imsg_composev
()
is similar to imsg_compose
(). It takes the same
parameters, except that the ancillary data buffer is specified by
iovec.
imsg_compose_ibuf
()
is similar to imsg_compose
(). It takes the same
parameters, except that the ancillary data buffer is specified by an ibuf
buf. This routine returns 1 if it succeeds, -1
otherwise. In either case the buffer buf is consumed
by the function.
imsg_forward
()
forwards a just received msg unaltered on
imsgbuf. File descriptors are not forwarded by this
function. It is possible to call imsg_forward
() more
than once per message.
imsg_get
()
fills in an individual imsg pending on imsgbuf into
the structure pointed to by imsg. It returns the total
size of the message, 0 if no messages are ready, or -1 for an error.
Received messages are returned as a
struct
imsg, which must be freed by
imsg_free
()
when no longer required.
The accessors
imsg_get_type
(),
imsg_get_pid
(),
imsg_get_id
(),
and
imsg_get_len
(),
return the type, pid,
id, and payload length used in
imsg_create
() to build the
imsg. If there is no payload
imsg_get_len
() returns 0.
imsg_get_fd
()
returns the file descriptor and passes the responsibility to track the
descriptor back to the program. Unclaimed file descriptors are closed by
imsg_free
().
imsg_get_data
()
and
imsg_get_ibuf
()
are used to extract the payload of an imsg.
imsg_get_data
() can be used if the structure of the
payload is known and can be extracted in one go. 0 is returned on success
and -1 on failure. imsg_get_ibuf
() initializes the
passed ibuf to hold the payload which can be read
using ibuf_get(3). The ibuf remains valid until
imsg_free
() is called and there is no need to call
ibuf_free
()
on this stack based buffer. The function returns 0 on success, -1
otherwise.
MAX_IMSGSIZE is defined as the maximum size of a single imsg, currently 16384 bytes.
EXAMPLES
In a typical program, a channel between two processes is created with socketpair(2), and an imsgbuf created around one file descriptor in each process:
struct imsgbuf parent_ibuf, child_ibuf; int imsg_fds[2]; if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_fds) == -1) err(1, "socketpair"); switch (fork()) { case -1: err(1, "fork"); case 0: /* child */ close(imsg_fds[0]); if (imsgbuf_init(&child_ibuf, imsg_fds[1]) == -1) err(1, NULL); exit(child_main(&child_ibuf)); } /* parent */ close(imsg_fds[1]); if (imsgbuf_init(&parent_ibuf, imsg_fds[0]) == -1) err(1, NULL); exit(parent_main(&parent_ibuf));
Messages may then be composed and queued on the
imsgbuf, for example using the
imsg_compose
() function:
enum imsg_type { IMSG_A_MESSAGE, IMSG_MESSAGE2 }; int child_main(struct imsgbuf *imsgbuf) { int idata; ... idata = 42; imsg_compose(imsgbuf, IMSG_A_MESSAGE, 0, 0, -1, &idata, sizeof idata); ... }
A mechanism such as poll(2) or the
event(3)
library is used to monitor the socket file descriptor. When the socket is
ready for writing, queued messages are transmitted with
imsgbuf_write
():
if (imsgbuf_write(imsgbuf) == -1) { if (errno == EPIPE) /* handle closed connection */ else /* handle write failure */ }
And when ready for reading, messages are first received using
imsgbuf_read
() and then extracted with
imsg_get
():
void dispatch_imsg(struct imsgbuf *imsgbuf) { struct imsg imsg; ssize_t n; int idata; switch (imsgbuf_read(imsgbuf)) { case -1: /* handle read error */ break; case 0: /* handle closed connection */ break; } for (;;) { if ((n = imsg_get(imsgbuf, &imsg)) == -1) { /* handle read error */ } if (n == 0) /* no more messages */ return; switch (imsg_get_type(&imsg)) { case IMSG_A_MESSAGE: if (imsg_get_data(&imsg, &idata, sizeof(idata)) == -1) { /* handle corrupt message */ } /* handle message received */ break; ... } imsg_free(&imsg); } }