|
|
- .\" $OpenBSD: imsg_init.3,v 1.4 2011/03/05 15:05:39 claudio Exp $
- .\"
- .\" Copyright (c) 2010 Nicholas Marriott <nicm@openbsd.org>
- .\"
- .\" Permission to use, copy, modify, and distribute this software for any
- .\" purpose with or without fee is hereby granted, provided that the above
- .\" copyright notice and this permission notice appear in all copies.
- .\"
- .\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- .\" WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
- .\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
- .\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- .\"
- .Dd $Mdocdate: March 5 2011 $
- .Dt IMSG_INIT 3
- .Os
- .Sh NAME
- .Nm imsg_init ,
- .Nm imsg_read ,
- .Nm imsg_get ,
- .Nm imsg_compose ,
- .Nm imsg_composev ,
- .Nm imsg_create ,
- .Nm imsg_add ,
- .Nm imsg_close ,
- .Nm imsg_free ,
- .Nm imsg_flush ,
- .Nm imsg_clear ,
- .Nm ibuf_open ,
- .Nm ibuf_dynamic ,
- .Nm ibuf_add ,
- .Nm ibuf_reserve ,
- .Nm ibuf_seek ,
- .Nm ibuf_size ,
- .Nm ibuf_left ,
- .Nm ibuf_close ,
- .Nm ibuf_write ,
- .Nm ibuf_free ,
- .Nm msgbuf_init ,
- .Nm msgbuf_clear ,
- .Nm msgbuf_write ,
- .Nm msgbuf_drain
- .Nd IPC messaging functions
- .Sh SYNOPSIS
- .Fd #include <sys/types.h>
- .Fd #include <sys/queue.h>
- .Fd #include <sys/uio.h>
- .Fd #include <imsg.h>
- .Ft void
- .Fn imsg_init "struct imsgbuf *ibuf" "int fd"
- .Ft ssize_t
- .Fn imsg_read "struct imsgbuf *ibuf"
- .Ft size_t
- .Fn imsg_get "struct imsgbuf *ibuf" "struct imsg *imsg"
- .Ft int
- .Fn imsg_compose "struct imsgbuf *ibuf" "u_int32_t type" "uint32_t peerid" \
- "pid_t pid" "int fd" "void *data" "u_int16_t datalen"
- .Ft int
- .Fn imsg_composev "struct imsgbuf *ibuf" "u_int32_t type" "u_int32_t peerid" \
- "pid_t pid" "int fd" "const struct iovec *iov" "int iovcnt"
- .Ft "struct ibuf *"
- .Fn imsg_create "struct imsgbuf *ibuf" "u_int32_t type" "u_int32_t peerid" \
- "pid_t pid" "u_int16_t datalen"
- .Ft int
- .Fn imsg_add "struct ibuf *buf" "void *data" "u_int16_t datalen"
- .Ft void
- .Fn imsg_close "struct imsgbuf *ibuf" "struct ibuf *msg"
- .Ft void
- .Fn imsg_free "struct imsg *imsg"
- .Ft int
- .Fn imsg_flush "struct imsgbuf *ibuf"
- .Ft void
- .Fn imsg_clear "struct imsgbuf *ibuf"
- .Ft "struct ibuf *"
- .Fn ibuf_open "size_t len"
- .Ft "struct ibuf *"
- .Fn ibuf_dynamic "size_t len" "size_t max"
- .Ft int
- .Fn ibuf_add "struct ibuf *buf" "const void *data" "size_t len"
- .Ft "void *"
- .Fn ibuf_reserve "struct ibuf *buf" "size_t len"
- .Ft "void *"
- .Fn ibuf_seek "struct ibuf *buf" "size_t pos" "size_t len"
- .Ft size_t
- .Fn ibuf_size "struct ibuf *buf"
- .Ft size_t
- .Fn ibuf_left "struct ibuf *buf"
- .Ft void
- .Fn ibuf_close "struct msgbuf *msgbuf" "struct ibuf *buf"
- .Ft int
- .Fn ibuf_write "struct msgbuf *msgbuf"
- .Ft void
- .Fn ibuf_free "struct ibuf *buf"
- .Ft void
- .Fn msgbuf_init "struct msgbuf *msgbuf"
- .Ft void
- .Fn msgbuf_clear "struct msgbuf *msgbuf"
- .Ft int
- .Fn msgbuf_write "struct msgbuf *msgbuf"
- .Ft void
- .Fn msgbuf_drain "struct msgbuf *msgbuf" "size_t n"
- .Sh DESCRIPTION
- The
- .Nm imsg
- functions provide a simple mechanism for communication between 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.
- .Pp
- A program using these functions should be linked with
- .Em -lutil .
- .Pp
- The basic
- .Nm
- structure is the
- .Em imsgbuf ,
- which wraps a file descriptor and represents one side of a channel on which
- messages are sent and received:
- .Bd -literal -offset indent
- struct imsgbuf {
- TAILQ_HEAD(, imsg_fd) fds;
- struct ibuf_read r;
- struct msgbuf w;
- int fd;
- pid_t pid;
- };
- .Ed
- .Pp
- .Fn imsg_init
- is a routine which initializes
- .Fa ibuf
- as one side of a channel associated with
- .Fa 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
- .Em w
- member as the output buffer queue,
- .Em fd
- with the file descriptor passed to
- .Fn imsg_init
- and the other members for internal use only.
- .Pp
- The
- .Fn imsg_clear
- function frees any data allocated as part of an imsgbuf.
- .Pp
- .Fn imsg_create ,
- .Fn imsg_add
- and
- .Fn imsg_close
- are generic construction routines for messages that are to be sent using an
- imsgbuf.
- .Pp
- .Fn imsg_create
- creates a new message with header specified by
- .Fa type ,
- .Fa peerid
- ands
- .Fa pid .
- A
- .Fa pid
- of zero uses the process ID returned by
- .Xr getpid 2
- when
- .Fa ibuf
- was initialized.
- In addition to this common imsg header,
- .Fa datalen
- bytes of space may be reserved for attaching to this imsg.
- This space is populated using
- .Fn imsg_add .
- Additionally, the file descriptor
- .Fa fd
- may be passed over the socket to the other process.
- If
- .Fa 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.
- .Fn imsg_create
- returns a pointer to a new message if it succeeds, NULL otherwise.
- .Pp
- .Fn imsg_add
- appends to
- .Fa imsg
- .Fa len
- bytes of ancillary data pointed to by
- .Fa buf .
- It returns
- .Fa len
- if it succeeds, \-1 otherwise.
- .Pp
- .Fn imsg_close
- completes creation of
- .Fa imsg
- by adding it to
- .Fa imsgbuf
- output buffer.
- .Pp
- .Fn imsg_compose
- is a routine which is used to quickly create and queue an imsg.
- It takes the same parameters as the
- .Fn imsg_create ,
- .Fn imsg_add
- and
- .Fn imsg_close
- routines,
- except that only one ancillary data buffer can be provided.
- This routine returns 1 if it succeeds, \-1 otherwise.
- .Pp
- .Fn imsg_composev
- is similar to
- .Fn imsg_compose .
- It takes the same parameters, except that the ancillary data buffer is specified
- by
- .Fa iovec .
- .Pp
- .Fn imsg_flush
- is a function which calls
- .Fn msgbuf_write
- in a loop until all imsgs in the output buffer are sent.
- It returns 0 if it succeeds, \-1 otherwise.
- .Pp
- The
- .Fn imsg_read
- routine reads pending data with
- .Xr recvmsg 2
- and queues it as individual messages on
- .Fa imsgbuf .
- It returns the number of bytes read on success, or \-1 on error.
- A return value of \-1 from
- .Fn imsg_read
- invalidates
- .Fa imsgbuf ,
- and renders it suitable only for passing to
- .Fn imsg_clear .
- .Pp
- .Fn imsg_get
- fills in an individual imsg pending on
- .Fa imsgbuf
- into the structure pointed to by
- .Fa 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
- .Em struct imsg ,
- which must be freed by
- .Fn imsg_free
- when no longer required.
- .Em struct imsg
- has this form:
- .Bd -literal -offset indent
- struct imsg {
- struct imsg_hdr hdr;
- int fd;
- void *data;
- };
-
- struct imsg_hdr {
- u_int32_t type;
- u_int16_t len;
- u_int16_t flags;
- u_int32_t peerid;
- u_int32_t pid;
- };
- .Ed
- .Pp
- The header members are:
- .Bl -tag -width Ds -offset indent
- .It type
- A integer identifier, typically used to express the meaning of the message.
- .It len
- The total length of the imsg, including the header and any ancillary data
- transmitted with the message (pointed to by the
- .Em data
- member of the message itself).
- .It flags
- Flags used internally by the imsg functions: should not be used by application
- programs.
- .It peerid, pid
- 32-bit values specified on message creation and free for any use by the
- caller, normally used to identify the message sender.
- .El
- .Pp
- In addition,
- .Em struct imsg
- has the following:
- .Bl -tag -width Ds -offset indent
- .It 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.
- .It data
- A pointer to the ancillary data transmitted with the imsg.
- .El
- .Pp
- The IMSG_HEADER_SIZE define is the size of the imsg message header, which
- may be subtracted from the
- .Fa len
- member of
- .Em struct imsg_hdr
- to obtain the length of any additional data passed with the message.
- .Pp
- MAX_IMSGSIZE is defined as the maximum size of a single imsg, currently
- 16384 bytes.
- .Sh BUFFERS
- The imsg API defines functions to manipulate buffers, used internally and during
- construction of imsgs with
- .Fn imsg_create .
- A
- .Em struct ibuf
- is a single buffer and a
- .Em struct msgbuf
- a queue of output buffers for transmission:
- .Bd -literal -offset indent
- struct ibuf {
- TAILQ_ENTRY(buf) entry;
- u_char *buf;
- size_t size;
- size_t max;
- size_t wpos;
- size_t rpos;
- int fd;
- };
-
- struct msgbuf {
- TAILQ_HEAD(, buf) bufs;
- u_int32_t queued;
- int fd;
- };
- .Ed
- .Pp
- The
- .Fn ibuf_open
- function allocates a fixed-length buffer.
- The buffer may not be resized and may contain a maximum of
- .Fa len
- bytes.
- On success
- .Fn ibuf_open
- returns a pointer to the buffer; on failure it returns NULL.
- .Pp
- .Fn ibuf_dynamic
- allocates a resizeable buffer of initial length
- .Fa len
- and maximum size
- .Fa max .
- Buffers allocated with
- .Fn ibuf_dynamic
- are automatically grown if necessary when data is added.
- .Pp
- .Fn ibuf_add
- is a routine which appends a block of data to
- .Fa buf .
- 0 is returned on success and \-1 on failure.
- .Pp
- .Fn ibuf_reserve
- is used to reserve
- .Fa len
- bytes in
- .Fa buf .
- A pointer to the start of the reserved space is returned, or NULL on error.
- .Pp
- .Fn ibuf_seek
- is a function which returns a pointer to the part of the buffer at offset
- .Fa pos
- and of extent
- .Fa len .
- NULL is returned if the requested range is outside the part of the buffer
- in use.
- .Pp
- .Fn ibuf_size
- and
- .Fn ibuf_left
- are functions which return the total bytes used and available in
- .Fa buf
- respectively.
- .Pp
- .Fn ibuf_close
- appends
- .Fa buf
- to
- .Fa msgbuf
- ready to be sent.
- .Pp
- The
- .Fn ibuf_write
- routine transmits as many pending buffers as possible from
- .Fn msgbuf
- using
- .Xr writev 2 .
- It returns 0 if it succeeds, \-1 on error and \-2 when an EOF condition on the
- socket is detected.
- .Pp
- .Fn ibuf_free
- frees
- .Fa buf
- and any associated storage.
- .Pp
- The
- .Fn msgbuf_init
- function initializes
- .Fa msgbuf
- so that buffers may be appended to it.
- The
- .Em fd
- member should also be set directly before
- .Fn msgbuf_write
- is used.
- .Pp
- .Fn msgbuf_clear
- empties a msgbuf, removing and discarding any queued buffers.
- .Pp
- The
- .Fn msgbuf_write
- routine calls
- .Xr sendmsg 2
- to transmit buffers queued in
- .Fa msgbuf .
- It returns 0 if it succeeds, \-1 on error, or \-2 when an EOF condition on the
- socket is detected.
- .Pp
- .Fn msgbuf_drain
- discards data from buffers queued in
- .Fa msgbuf
- until
- .Fa n
- bytes have been removed or
- .Fa msgbuf
- is empty.
- .Sh EXAMPLES
- In a typical program, a channel between two processes is created with
- .Xr socketpair 2 ,
- and an
- .Em imsgbuf
- created around one file descriptor in each process:
- .Bd -literal -offset indent
- 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));
- .Ed
- .Pp
- Messages may then be composed and queued on the
- .Em imsgbuf ,
- for example using the
- .Fn imsg_compose
- function:
- .Bd -literal -offset indent
- 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);
- ...
- }
- .Ed
- .Pp
- A mechanism such as
- .Xr poll 2
- or the
- .Xr event 3
- library is used to monitor the socket file descriptor.
- When the socket is ready for writing, queued messages are transmitted with
- .Fn msgbuf_write :
- .Bd -literal -offset indent
- if (msgbuf_write(&ibuf-\*(Gtw) \*(Lt 0) {
- /* handle write failure */
- }
- .Ed
- .Pp
- And when ready for reading, messages are first received using
- .Fn imsg_read
- and then extracted with
- .Fn imsg_get :
- .Bd -literal -offset indent
- void
- dispatch_imsg(struct imsgbuf *ibuf)
- {
- struct imsg imsg;
- ssize_t n, datalen;
- int idata;
-
- if ((n = imsg_read(ibuf)) == -1 || n == 0) {
- /* handle socket error */
- }
-
- 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 \*(Lt sizeof idata) {
- /* handle corrupt message */
- }
- memcpy(&idata, imsg.data, sizeof idata);
- /* handle message received */
- break;
- ...
- }
-
- imsg_free(&imsg);
- }
- }
- .Ed
- .Sh SEE ALSO
- .Xr socketpair 2 ,
- .Xr unix 4
|