NAME
imsg_init
,
imsg_read
, imsg_get
,
imsg_get_ibuf
,
imsg_get_data
, imsg_get_fd
,
imsg_get_id
, imsg_get_len
,
imsg_get_pid
, imsg_get_type
,
imsg_compose
, imsg_composev
,
imsg_compose_ibuf
,
imsg_create
, imsg_add
,
imsg_close
, imsg_forward
,
imsg_free
, imsg_flush
,
imsg_clear
—
IPC messaging functions
SYNOPSIS
#include
<sys/queue.h>
#include <imsg.h>
void
imsg_init
(struct
imsgbuf *imsgbuf, int
fd);
ssize_t
imsg_read
(struct
imsgbuf *imsgbuf);
ssize_t
imsg_get
(struct
imsgbuf *imsgbuf, struct
imsg *imsg);
int
imsg_get_ibuf
(struct
imsg *imsg, struct ibuf
*ibuf);
int
imsg_get_data
(struct
imsg *imsg, void
*data, size_t
len);
int
imsg_get_fd
(struct
imsg *imsg);
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);
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_add
(struct
ibuf *msg, const void
*data, size_t
datalen);
void
imsg_close
(struct
imsgbuf *imsgbuf, struct
ibuf *msg);
void
imsg_free
(struct
imsg *imsg);
int
imsg_forward
(struct
imsgbuf *imsgbuf, struct
imsg *msg);
int
imsg_flush
(struct
imsgbuf *imsgbuf);
void
imsg_clear
(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.
The basic imsg_init
structure is the
imsgbuf, which wraps a file descriptor and represents one
side of a channel on which messages are sent and received:
struct imsgbuf { TAILQ_HEAD(, imsg_fd) fds; struct ibuf_read r; struct msgbuf w; int fd; pid_t pid; };
imsg_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.
An imsgbuf is initialized with the
w member as the
output buffer queue,
fd with the
file descriptor passed to imsg_init
() and the other
members for internal use only.
The
imsg_clear
()
function frees any data allocated as part of an imsgbuf.
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. Any attached file descriptor is closed.
imsg_flush
()
calls
msgbuf_write
()
in a loop until all imsgs in the output buffer are sent. It returns 0 if it
succeeds, -1 otherwise.
The
imsg_read
()
routine reads pending data with
recvmsg(2) and queues it as individual messages on
imsgbuf. It returns the number of bytes read on
success, or -1 on error. A return value of -1 from
imsg_read
() invalidates
imsgbuf, and renders it suitable only for passing to
imsg_clear
().
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.
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]); imsg_init(&child_ibuf, imsg_fds[1]); exit(child_main(&child_ibuf)); } /* parent */ close(imsg_fds[1]); imsg_init(&parent_ibuf, imsg_fds[0]); 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
msgbuf_write
():
if ((n = msgbuf_write(&imsgbuf->w)) == -1 && errno != EAGAIN) { /* handle write failure */ } if (n == 0) { /* handle closed connection */ }
And when ready for reading, messages are first received using
imsg_read
() and then extracted with
imsg_get
():
void dispatch_imsg(struct imsgbuf *imsgbuf) { struct imsg imsg; ssize_t n; int idata; if ((n = imsg_read(imsgbuf)) == -1 && errno != EAGAIN) { /* handle read error */ } if (n == 0) { /* handle closed connection */ } 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); } }