NAME
imsg_init
,
imsg_read
, imsg_get
,
imsg_compose
, imsg_composev
,
imsg_compose_ibuf
,
imsg_create
, imsg_add
,
imsg_close
, imsg_free
,
imsg_flush
, imsg_clear
,
ibuf_open
, ibuf_dynamic
,
ibuf_add
, ibuf_add_buf
,
ibuf_add_n8
, ibuf_add_n16
,
ibuf_add_n32
, ibuf_add_n64
,
ibuf_add_zero
, ibuf_reserve
,
ibuf_seek
, ibuf_set
,
ibuf_set_n8
, ibuf_set_n16
,
ibuf_set_n32
, ibuf_set_n64
,
ibuf_data
, ibuf_size
,
ibuf_left
, ibuf_close
,
ibuf_free
, ibuf_fd_avail
,
ibuf_fd_get
, ibuf_fd_set
,
ibuf_write
, msgbuf_init
,
msgbuf_clear
, msgbuf_write
— IPC messaging
functions
SYNOPSIS
#include
<sys/types.h>
#include <sys/queue.h>
#include <sys/uio.h>
#include <stdint.h>
#include <imsg.h>
void
imsg_init
(struct
imsgbuf *ibuf, int
fd);
ssize_t
imsg_read
(struct
imsgbuf *ibuf);
ssize_t
imsg_get
(struct
imsgbuf *ibuf, struct
imsg *imsg);
int
imsg_compose
(struct
imsgbuf *ibuf, uint32_t
type, uint32_t
peerid, pid_t pid,
int fd,
const void *data,
uint16_t datalen);
int
imsg_composev
(struct
imsgbuf *ibuf, uint32_t
type, uint32_t
peerid, pid_t pid,
int fd,
const struct iovec *iov,
int iovcnt);
int
imsg_compose_ibuf
(struct
imsgbuf *ibuf, uint32_t
type, uint32_t
peerid, pid_t pid,
struct ibuf *buf);
struct ibuf *
imsg_create
(struct
imsgbuf *ibuf, uint32_t
type, uint32_t
peerid, pid_t pid,
uint16_t datalen);
int
imsg_add
(struct
ibuf *msg, const void
*data, uint16_t
datalen);
void
imsg_close
(struct
imsgbuf *ibuf, struct
ibuf *msg);
void
imsg_free
(struct
imsg *imsg);
int
imsg_flush
(struct
imsgbuf *ibuf);
void
imsg_clear
(struct
imsgbuf *ibuf);
struct ibuf *
ibuf_open
(size_t
len);
struct ibuf *
ibuf_dynamic
(size_t
len, size_t
max);
int
ibuf_add
(struct
ibuf *buf, const void
*data, size_t
len);
int
ibuf_add_buf
(struct
ibuf *buf, const struct
ibuf *from);
int
ibuf_add_n8
(struct
ibuf *buf, uint64_t
value);
int
ibuf_add_n16
(struct
ibuf *buf, uint64_t
value);
int
ibuf_add_n32
(struct
ibuf *buf, uint64_t
value);
int
ibuf_add_n64
(struct
ibuf *buf, uint64_t
value);
int
ibuf_add_zero
(struct
ibuf *buf, size_t
len);
void *
ibuf_reserve
(struct
ibuf *buf, size_t
len);
void *
ibuf_seek
(struct
ibuf *buf, size_t
pos, size_t
len);
int
ibuf_set
(struct
ibuf *buf, size_t
pos, const void
*data, size_t
len);
int
ibuf_set_n8
(struct
ibuf *buf, size_t
pos, uint64_t
value);
int
ibuf_set_n16
(struct
ibuf *buf, size_t
pos, uint64_t
value);
int
ibuf_set_n32
(struct
ibuf *buf, size_t
pos, uint64_t
value);
int
ibuf_set_n64
(struct
ibuf *buf, size_t
pos, uint64_t
value);
void *
ibuf_data
(struct
ibuf *buf);
size_t
ibuf_size
(struct
ibuf *buf);
size_t
ibuf_left
(struct
ibuf *buf);
void
ibuf_close
(struct
msgbuf *msgbuf, struct
ibuf *buf);
void
ibuf_free
(struct
ibuf *buf);
int
ibuf_fd_avail
(struct
ibuf *buf);
int
ibuf_fd_get
(struct
ibuf *buf);
void
ibuf_fd_set
(struct
ibuf *buf, int
fd);
int
ibuf_write
(struct
msgbuf *msgbuf);
void
msgbuf_init
(struct
msgbuf *msgbuf);
void
msgbuf_clear
(struct
msgbuf *msgbuf);
int
msgbuf_write
(struct
msgbuf *msgbuf);
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 ibuf 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,
peerid and pid. A
pid of zero uses the process ID returned by
getpid(2)
when ibuf 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
ibuf 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_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. struct imsg has this form:
struct imsg { struct imsg_hdr hdr; int fd; void *data; }; struct imsg_hdr { uint32_t type; uint16_t len; uint16_t flags; uint32_t peerid; uint32_t pid; };
The header members are:
- type
- A integer identifier, typically used to express the meaning of the message.
- len
- The total length of the imsg, including the header and any ancillary data transmitted with the message (pointed to by the data member of the message itself).
- flags
- Flags used internally by the imsg functions: should not be used by application programs.
- peerid, pid
- 32-bit values specified on message creation and free for any use by the caller, normally used to identify the message sender.
In addition, struct imsg has the following:
- fd
- The file descriptor specified when the message was created and passed using the socket control message API, or -1 if no file descriptor was sent.
- data
- A pointer to the ancillary data transmitted with the imsg.
The IMSG_HEADER_SIZE define is the size of the imsg message header, which may be subtracted from the len member of struct imsg_hdr to obtain the length of any additional data passed with the message.
MAX_IMSGSIZE is defined as the maximum size of a single imsg, currently 16384 bytes.
BUFFERS
The imsg API defines functions to manipulate buffers, used
internally and during construction of imsgs with
imsg_create
().
A struct ibuf is a single buffer and a
struct msgbuf a queue of output buffers for
transmission:
struct ibuf { TAILQ_ENTRY(ibuf) entry; unsigned char *buf; size_t size; size_t max; size_t wpos; size_t rpos; int fd; }; struct msgbuf { TAILQ_HEAD(, ibuf) bufs; uint32_t queued; int fd; };
The
ibuf_open
()
function allocates a fixed-length buffer. The buffer may not be resized and
may contain a maximum of len bytes. On success
ibuf_open
() returns a pointer to the buffer; on
failure it returns NULL.
ibuf_dynamic
()
allocates a resizeable buffer of initial length len
and maximum size max. Buffers allocated with
ibuf_dynamic
() are automatically grown if necessary
when data is added.
ibuf_add
()
appends a block of data to buf. 0 is returned on
success and -1 on failure.
ibuf_add_buf
()
appends the buffer from to buf.
0 is returned on success and -1 on failure.
ibuf_add_n8
(),
ibuf_add_n16
(),
ibuf_add_n32
(),
and
ibuf_add_n64
()
add a 1-byte, 2-byte, 4-byte, and 8-byte value to
buf in network byte order. This function checks
value to not overflow. 0 is returned on success and -1
on failure.
ibuf_add_zero
()
appends a block of zeros to buf. 0 is returned on
success and -1 on failure.
ibuf_reserve
()
is used to reserve len bytes in
buf. A pointer to the start of the reserved space is
returned, or NULL on error.
ibuf_seek
()
returns a pointer to the part of the buffer at offset
pos and of extent len. NULL is
returned if the requested range is outside the part of the buffer in
use.
ibuf_set
()
replaces a part of buf at offset
pos with the data of extent
len. 0 is returned on success and -1 on failure.
ibuf_set_n8
(),
ibuf_set_n16
(),
ibuf_set_n32
()
and
ibuf_set_n64
()
replace a 1-byte, 2-byte, 4-byte or 8-byte value at
offset pos in the buffer buf in
network byte order. This function checks value to not
overflow. 0 is returned on success and -1 on failure.
ibuf_data
()
returns the pointer to the internal buffer. This function should only be
used together with ibuf_size
() to process a
previously generated buffer.
ibuf_size
()
and
ibuf_left
()
are functions which return the total bytes used and available in
buf respectively.
ibuf_close
()
appends buf to msgbuf ready to
be sent.
ibuf_fd_avail
(),
ibuf_fd_get
()
and ibuf_fd_set
() are functions to check, get and
set the file descriptor assigned to buf. After calling
ibuf_fd_set
() the file descriptor is part of the
buf and will be transmitted or closed by the ibuf API.
Any previously set file descriptor will be closed before assigning a new
descriptor. ibuf_fd_get
() returns the file
descriptor and passes the responsibility to track the descriptor back to the
program. ibuf_fd_avail
() returns true if there is a
file descriptor set on buf.
ibuf_free
()
frees buf and any associated storage, and closes any
file descriptor set with
ibuf_fd_set
().
If buf is a NULL pointer, no action occurs.
The
ibuf_write
()
routine transmits as many pending buffers as possible from
msgbuf using
writev(2).
It returns 1 if it succeeds, -1 on error and 0 when no buffers were pending
or an EOF condition on the socket is detected. Temporary resource shortages
are returned with errno EAGAIN
and require the
application to retry again in the future.
The
msgbuf_init
()
function initializes msgbuf so that buffers may be
appended to it. The fd member should also be set directly
before msgbuf_write
() is used.
msgbuf_clear
()
empties a msgbuf, removing and discarding any queued buffers.
The
msgbuf_write
()
routine calls sendmsg(2) to transmit buffers queued in
msgbuf. It returns 1 if it succeeds, -1 on error, and
0 when the queue was empty or an EOF condition on the socket is detected.
Temporary resource shortages are returned with errno
EAGAIN
and require the application to retry again in
the future.
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 *ibuf) { int idata; ... idata = 42; imsg_compose(ibuf, 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(&ibuf->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 *ibuf) { struct imsg imsg; ssize_t n, datalen; int idata; if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) { /* handle read error */ } if (n == 0) { /* handle closed connection */ } for (;;) { if ((n = imsg_get(ibuf, &imsg)) == -1) { /* handle read error */ } if (n == 0) /* no more messages */ return; datalen = imsg.hdr.len - IMSG_HEADER_SIZE; switch (imsg.hdr.type) { case IMSG_A_MESSAGE: if (datalen < sizeof idata) { /* handle corrupt message */ } memcpy(&idata, imsg.data, sizeof idata); /* handle message received */ break; ... } imsg_free(&imsg); } }