xref: /openbsd-src/lib/libutil/imsg_init.3 (revision a0747c9f67a4ae71ccb71e62a28d1ea19e06a63c)
1.\" $OpenBSD: imsg_init.3,v 1.24 2020/12/15 13:40:22 jmc Exp $
2.\"
3.\" Copyright (c) 2010 Nicholas Marriott <nicm@openbsd.org>
4.\"
5.\" Permission to use, copy, modify, and distribute this software for any
6.\" purpose with or without fee is hereby granted, provided that the above
7.\" copyright notice and this permission notice appear in all copies.
8.\"
9.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13.\" WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
14.\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
15.\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16.\"
17.Dd $Mdocdate: December 15 2020 $
18.Dt IMSG_INIT 3
19.Os
20.Sh NAME
21.Nm imsg_init ,
22.Nm imsg_read ,
23.Nm imsg_get ,
24.Nm imsg_compose ,
25.Nm imsg_composev ,
26.Nm imsg_create ,
27.Nm imsg_add ,
28.Nm imsg_close ,
29.Nm imsg_free ,
30.Nm imsg_flush ,
31.Nm imsg_clear ,
32.Nm ibuf_open ,
33.Nm ibuf_dynamic ,
34.Nm ibuf_add ,
35.Nm ibuf_reserve ,
36.Nm ibuf_seek ,
37.Nm ibuf_size ,
38.Nm ibuf_left ,
39.Nm ibuf_close ,
40.Nm ibuf_write ,
41.Nm ibuf_free ,
42.Nm msgbuf_init ,
43.Nm msgbuf_clear ,
44.Nm msgbuf_write ,
45.Nm msgbuf_drain
46.Nd IPC messaging functions
47.Sh SYNOPSIS
48.In sys/types.h
49.In sys/queue.h
50.In sys/uio.h
51.In stdint.h
52.In imsg.h
53.Ft void
54.Fn imsg_init "struct imsgbuf *ibuf" "int fd"
55.Ft ssize_t
56.Fn imsg_read "struct imsgbuf *ibuf"
57.Ft ssize_t
58.Fn imsg_get "struct imsgbuf *ibuf" "struct imsg *imsg"
59.Ft int
60.Fn imsg_compose "struct imsgbuf *ibuf" "uint32_t type" "uint32_t peerid" \
61    "pid_t pid" "int fd" "const void *data" "uint16_t datalen"
62.Ft int
63.Fn imsg_composev "struct imsgbuf *ibuf" "uint32_t type" "uint32_t peerid" \
64    "pid_t pid" "int fd" "const struct iovec *iov" "int iovcnt"
65.Ft "struct ibuf *"
66.Fn imsg_create "struct imsgbuf *ibuf" "uint32_t type" "uint32_t peerid" \
67    "pid_t pid" "uint16_t datalen"
68.Ft int
69.Fn imsg_add "struct ibuf *msg" "const void *data" "uint16_t datalen"
70.Ft void
71.Fn imsg_close "struct imsgbuf *ibuf" "struct ibuf *msg"
72.Ft void
73.Fn imsg_free "struct imsg *imsg"
74.Ft int
75.Fn imsg_flush "struct imsgbuf *ibuf"
76.Ft void
77.Fn imsg_clear "struct imsgbuf *ibuf"
78.Ft "struct ibuf *"
79.Fn ibuf_open "size_t len"
80.Ft "struct ibuf *"
81.Fn ibuf_dynamic "size_t len" "size_t max"
82.Ft int
83.Fn ibuf_add "struct ibuf *buf" "const void *data" "size_t len"
84.Ft "void *"
85.Fn ibuf_reserve "struct ibuf *buf" "size_t len"
86.Ft "void *"
87.Fn ibuf_seek "struct ibuf *buf" "size_t pos" "size_t len"
88.Ft size_t
89.Fn ibuf_size "struct ibuf *buf"
90.Ft size_t
91.Fn ibuf_left "struct ibuf *buf"
92.Ft void
93.Fn ibuf_close "struct msgbuf *msgbuf" "struct ibuf *buf"
94.Ft int
95.Fn ibuf_write "struct msgbuf *msgbuf"
96.Ft void
97.Fn ibuf_free "struct ibuf *buf"
98.Ft void
99.Fn msgbuf_init "struct msgbuf *msgbuf"
100.Ft void
101.Fn msgbuf_clear "struct msgbuf *msgbuf"
102.Ft int
103.Fn msgbuf_write "struct msgbuf *msgbuf"
104.Ft void
105.Fn msgbuf_drain "struct msgbuf *msgbuf" "size_t n"
106.Sh DESCRIPTION
107The
108.Nm imsg
109functions provide a simple mechanism for communication between local processes
110using sockets.
111Each transmitted message is guaranteed to be presented to the receiving program
112whole.
113They are commonly used in privilege separated processes, where processes with
114different rights are required to cooperate.
115.Pp
116A program using these functions should be linked with
117.Em -lutil .
118.Pp
119The basic
120.Nm
121structure is the
122.Em imsgbuf ,
123which wraps a file descriptor and represents one side of a channel on which
124messages are sent and received:
125.Bd -literal -offset indent
126struct imsgbuf {
127	TAILQ_HEAD(, imsg_fd)	fds;
128	struct ibuf_read	r;
129	struct msgbuf		w;
130	int			fd;
131	pid_t			pid;
132};
133.Ed
134.Pp
135.Fn imsg_init
136is a routine which initializes
137.Fa ibuf
138as one side of a channel associated with
139.Fa fd .
140The file descriptor is used to send and receive messages,
141but is not closed by any of the imsg functions.
142An imsgbuf is initialized with the
143.Em w
144member as the output buffer queue,
145.Em fd
146with the file descriptor passed to
147.Fn imsg_init
148and the other members for internal use only.
149.Pp
150The
151.Fn imsg_clear
152function frees any data allocated as part of an imsgbuf.
153.Pp
154.Fn imsg_create ,
155.Fn imsg_add
156and
157.Fn imsg_close
158are generic construction routines for messages that are to be sent using an
159imsgbuf.
160.Pp
161.Fn imsg_create
162creates a new message with header specified by
163.Fa type ,
164.Fa peerid
165and
166.Fa pid .
167A
168.Fa pid
169of zero uses the process ID returned by
170.Xr getpid 2
171when
172.Fa ibuf
173was initialized.
174In addition to this common imsg header,
175.Fa datalen
176bytes of space may be reserved for attaching to this imsg.
177This space is populated using
178.Fn imsg_add .
179.Fn imsg_create
180returns a pointer to a new message if it succeeds, NULL otherwise.
181.Pp
182.Fn imsg_add
183appends to
184.Fa msg
185.Fa datalen
186bytes of ancillary data pointed to by
187.Fa data .
188It returns
189.Fa datalen
190if it succeeds, \-1 otherwise.
191.Pp
192.Fn imsg_close
193completes creation of
194.Fa msg
195by adding it to
196.Fa ibuf
197output buffer.
198.Pp
199.Fn imsg_compose
200is a routine which is used to quickly create and queue an imsg.
201It takes the same parameters as the
202.Fn imsg_create ,
203.Fn imsg_add
204and
205.Fn imsg_close
206routines,
207except that only one ancillary data buffer can be provided.
208Additionally, the file descriptor
209.Fa fd
210may be passed over the socket to the other process.
211If
212.Fa fd
213is given, it is closed in the sending program after the message is sent.
214A value of \-1 indicates no file descriptor should be passed.
215This routine returns 1 if it succeeds, \-1 otherwise.
216.Pp
217.Fn imsg_composev
218is similar to
219.Fn imsg_compose .
220It takes the same parameters, except that the ancillary data buffer is specified
221by
222.Fa iovec .
223.Pp
224.Fn imsg_flush
225is a function which calls
226.Fn msgbuf_write
227in a loop until all imsgs in the output buffer are sent.
228It returns 0 if it succeeds, \-1 otherwise.
229.Pp
230The
231.Fn imsg_read
232routine reads pending data with
233.Xr recvmsg 2
234and queues it as individual messages on
235.Fa imsgbuf .
236It returns the number of bytes read on success, or \-1 on error.
237A return value of \-1 from
238.Fn imsg_read
239invalidates
240.Fa imsgbuf ,
241and renders it suitable only for passing to
242.Fn imsg_clear .
243.Pp
244.Fn imsg_get
245fills in an individual imsg pending on
246.Fa imsgbuf
247into the structure pointed to by
248.Fa imsg .
249It returns the total size of the message, 0 if no messages are ready, or \-1
250for an error.
251Received messages are returned as a
252.Em struct imsg ,
253which must be freed by
254.Fn imsg_free
255when no longer required.
256.Em struct imsg
257has this form:
258.Bd -literal -offset indent
259struct imsg {
260	struct imsg_hdr	 hdr;
261	int		 fd;
262	void		*data;
263};
264
265struct imsg_hdr {
266	uint32_t	 type;
267	uint16_t	 len;
268	uint16_t	 flags;
269	uint32_t	 peerid;
270	uint32_t	 pid;
271};
272.Ed
273.Pp
274The header members are:
275.Bl -tag -width Ds -offset indent
276.It type
277A integer identifier, typically used to express the meaning of the message.
278.It len
279The total length of the imsg, including the header and any ancillary data
280transmitted with the message (pointed to by the
281.Em data
282member of the message itself).
283.It flags
284Flags used internally by the imsg functions: should not be used by application
285programs.
286.It peerid, pid
28732-bit values specified on message creation and free for any use by the
288caller, normally used to identify the message sender.
289.El
290.Pp
291In addition,
292.Em struct imsg
293has the following:
294.Bl -tag -width Ds -offset indent
295.It fd
296The file descriptor specified when the message was created and passed using the
297socket control message API, or \-1 if no file descriptor was sent.
298.It data
299A pointer to the ancillary data transmitted with the imsg.
300.El
301.Pp
302The IMSG_HEADER_SIZE define is the size of the imsg message header, which
303may be subtracted from the
304.Fa len
305member of
306.Em struct imsg_hdr
307to obtain the length of any additional data passed with the message.
308.Pp
309MAX_IMSGSIZE is defined as the maximum size of a single imsg, currently
31016384 bytes.
311.Sh BUFFERS
312The imsg API defines functions to manipulate buffers, used internally and during
313construction of imsgs with
314.Fn imsg_create .
315A
316.Em struct ibuf
317is a single buffer and a
318.Em struct msgbuf
319a queue of output buffers for transmission:
320.Bd -literal -offset indent
321struct ibuf {
322	TAILQ_ENTRY(ibuf)	 entry;
323	unsigned char		*buf;
324	size_t			 size;
325	size_t			 max;
326	size_t			 wpos;
327	size_t			 rpos;
328	int			 fd;
329};
330
331struct msgbuf {
332	TAILQ_HEAD(, ibuf)	 bufs;
333	uint32_t		 queued;
334	int			 fd;
335};
336.Ed
337.Pp
338The
339.Fn ibuf_open
340function allocates a fixed-length buffer.
341The buffer may not be resized and may contain a maximum of
342.Fa len
343bytes.
344On success
345.Fn ibuf_open
346returns a pointer to the buffer; on failure it returns NULL.
347.Pp
348.Fn ibuf_dynamic
349allocates a resizeable buffer of initial length
350.Fa len
351and maximum size
352.Fa max .
353Buffers allocated with
354.Fn ibuf_dynamic
355are automatically grown if necessary when data is added.
356.Pp
357.Fn ibuf_add
358is a routine which appends a block of data to
359.Fa buf .
3600 is returned on success and \-1 on failure.
361.Pp
362.Fn ibuf_reserve
363is used to reserve
364.Fa len
365bytes in
366.Fa buf .
367A pointer to the start of the reserved space is returned, or NULL on error.
368.Pp
369.Fn ibuf_seek
370is a function which returns a pointer to the part of the buffer at offset
371.Fa pos
372and of extent
373.Fa len .
374NULL is returned if the requested range is outside the part of the buffer
375in use.
376.Pp
377.Fn ibuf_size
378and
379.Fn ibuf_left
380are functions which return the total bytes used and available in
381.Fa buf
382respectively.
383.Pp
384.Fn ibuf_close
385appends
386.Fa buf
387to
388.Fa msgbuf
389ready to be sent.
390.Pp
391The
392.Fn ibuf_write
393routine transmits as many pending buffers as possible from
394.Fa msgbuf
395using
396.Xr writev 2 .
397It returns 1 if it succeeds, \-1 on error and 0 when no buffers were
398pending or an EOF condition on the socket is detected.
399Temporary resource shortages are returned with errno
400.Er EAGAIN
401and require the application to retry again in the future.
402.Pp
403.Fn ibuf_free
404frees
405.Fa buf
406and any associated storage.
407If
408.Fa buf
409is a NULL pointer, no action occurs.
410.Pp
411The
412.Fn msgbuf_init
413function initializes
414.Fa msgbuf
415so that buffers may be appended to it.
416The
417.Em fd
418member should also be set directly before
419.Fn msgbuf_write
420is used.
421.Pp
422.Fn msgbuf_clear
423empties a msgbuf, removing and discarding any queued buffers.
424.Pp
425The
426.Fn msgbuf_write
427routine calls
428.Xr sendmsg 2
429to transmit buffers queued in
430.Fa msgbuf .
431It returns 1 if it succeeds, \-1 on error, and 0 when the queue was empty
432or an EOF condition on the socket is detected.
433Temporary resource shortages are returned with errno
434.Er EAGAIN
435and require the application to retry again in the future.
436.Pp
437.Fn msgbuf_drain
438discards data from buffers queued in
439.Fa msgbuf
440until
441.Fa n
442bytes have been removed or
443.Fa msgbuf
444is empty.
445.Sh EXAMPLES
446In a typical program, a channel between two processes is created with
447.Xr socketpair 2 ,
448and an
449.Em imsgbuf
450created around one file descriptor in each process:
451.Bd -literal -offset indent
452struct imsgbuf	parent_ibuf, child_ibuf;
453int		imsg_fds[2];
454
455if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_fds) == -1)
456	err(1, "socketpair");
457
458switch (fork()) {
459case -1:
460	err(1, "fork");
461case 0:
462	/* child */
463	close(imsg_fds[0]);
464	imsg_init(&child_ibuf, imsg_fds[1]);
465	exit(child_main(&child_ibuf));
466}
467
468/* parent */
469close(imsg_fds[1]);
470imsg_init(&parent_ibuf, imsg_fds[0]);
471exit(parent_main(&parent_ibuf));
472.Ed
473.Pp
474Messages may then be composed and queued on the
475.Em imsgbuf ,
476for example using the
477.Fn imsg_compose
478function:
479.Bd -literal -offset indent
480enum imsg_type {
481	IMSG_A_MESSAGE,
482	IMSG_MESSAGE2
483};
484
485int
486child_main(struct imsgbuf *ibuf)
487{
488	int	idata;
489	...
490	idata = 42;
491	imsg_compose(ibuf, IMSG_A_MESSAGE,
492	    0, 0, -1, &idata, sizeof idata);
493	...
494}
495.Ed
496.Pp
497A mechanism such as
498.Xr poll 2
499or the
500.Xr event 3
501library is used to monitor the socket file descriptor.
502When the socket is ready for writing, queued messages are transmitted with
503.Fn msgbuf_write :
504.Bd -literal -offset indent
505	if ((n = msgbuf_write(&ibuf-\*(Gtw)) == -1 && errno != EAGAIN) {
506		/* handle write failure */
507	}
508	if (n == 0) {
509		/* handle closed connection */
510	}
511.Ed
512.Pp
513And when ready for reading, messages are first received using
514.Fn imsg_read
515and then extracted with
516.Fn imsg_get :
517.Bd -literal -offset indent
518void
519dispatch_imsg(struct imsgbuf *ibuf)
520{
521	struct imsg	imsg;
522	ssize_t         n, datalen;
523	int		idata;
524
525	if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) {
526		/* handle read error */
527	}
528	if (n == 0) {
529		/* handle closed connection */
530	}
531
532	for (;;) {
533		if ((n = imsg_get(ibuf, &imsg)) == -1) {
534			/* handle read error */
535		}
536		if (n == 0)	/* no more messages */
537			return;
538		datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
539
540		switch (imsg.hdr.type) {
541		case IMSG_A_MESSAGE:
542			if (datalen \*(Lt sizeof idata) {
543				/* handle corrupt message */
544			}
545			memcpy(&idata, imsg.data, sizeof idata);
546			/* handle message received */
547			break;
548		...
549		}
550
551		imsg_free(&imsg);
552	}
553}
554.Ed
555.Sh SEE ALSO
556.Xr socketpair 2 ,
557.Xr unix 4
558