xref: /openbsd-src/lib/libutil/imsg_init.3 (revision fc405d53b73a2d73393cb97f684863d17b583e38)
1.\" $OpenBSD: imsg_init.3,v 1.25 2022/05/19 08:05:23 stsp 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: May 19 2022 $
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, otherwise
191.Fa msg
192is freed and \-1 is returned.
193.Pp
194.Fn imsg_close
195completes creation of
196.Fa msg
197by adding it to
198.Fa ibuf
199output buffer.
200.Pp
201.Fn imsg_compose
202is a routine which is used to quickly create and queue an imsg.
203It takes the same parameters as the
204.Fn imsg_create ,
205.Fn imsg_add
206and
207.Fn imsg_close
208routines,
209except that only one ancillary data buffer can be provided.
210Additionally, the file descriptor
211.Fa fd
212may be passed over the socket to the other process.
213If
214.Fa fd
215is given, it is closed in the sending program after the message is sent.
216A value of \-1 indicates no file descriptor should be passed.
217This routine returns 1 if it succeeds, \-1 otherwise.
218.Pp
219.Fn imsg_composev
220is similar to
221.Fn imsg_compose .
222It takes the same parameters, except that the ancillary data buffer is specified
223by
224.Fa iovec .
225.Pp
226.Fn imsg_flush
227is a function which calls
228.Fn msgbuf_write
229in a loop until all imsgs in the output buffer are sent.
230It returns 0 if it succeeds, \-1 otherwise.
231.Pp
232The
233.Fn imsg_read
234routine reads pending data with
235.Xr recvmsg 2
236and queues it as individual messages on
237.Fa imsgbuf .
238It returns the number of bytes read on success, or \-1 on error.
239A return value of \-1 from
240.Fn imsg_read
241invalidates
242.Fa imsgbuf ,
243and renders it suitable only for passing to
244.Fn imsg_clear .
245.Pp
246.Fn imsg_get
247fills in an individual imsg pending on
248.Fa imsgbuf
249into the structure pointed to by
250.Fa imsg .
251It returns the total size of the message, 0 if no messages are ready, or \-1
252for an error.
253Received messages are returned as a
254.Em struct imsg ,
255which must be freed by
256.Fn imsg_free
257when no longer required.
258.Em struct imsg
259has this form:
260.Bd -literal -offset indent
261struct imsg {
262	struct imsg_hdr	 hdr;
263	int		 fd;
264	void		*data;
265};
266
267struct imsg_hdr {
268	uint32_t	 type;
269	uint16_t	 len;
270	uint16_t	 flags;
271	uint32_t	 peerid;
272	uint32_t	 pid;
273};
274.Ed
275.Pp
276The header members are:
277.Bl -tag -width Ds -offset indent
278.It type
279A integer identifier, typically used to express the meaning of the message.
280.It len
281The total length of the imsg, including the header and any ancillary data
282transmitted with the message (pointed to by the
283.Em data
284member of the message itself).
285.It flags
286Flags used internally by the imsg functions: should not be used by application
287programs.
288.It peerid, pid
28932-bit values specified on message creation and free for any use by the
290caller, normally used to identify the message sender.
291.El
292.Pp
293In addition,
294.Em struct imsg
295has the following:
296.Bl -tag -width Ds -offset indent
297.It fd
298The file descriptor specified when the message was created and passed using the
299socket control message API, or \-1 if no file descriptor was sent.
300.It data
301A pointer to the ancillary data transmitted with the imsg.
302.El
303.Pp
304The IMSG_HEADER_SIZE define is the size of the imsg message header, which
305may be subtracted from the
306.Fa len
307member of
308.Em struct imsg_hdr
309to obtain the length of any additional data passed with the message.
310.Pp
311MAX_IMSGSIZE is defined as the maximum size of a single imsg, currently
31216384 bytes.
313.Sh BUFFERS
314The imsg API defines functions to manipulate buffers, used internally and during
315construction of imsgs with
316.Fn imsg_create .
317A
318.Em struct ibuf
319is a single buffer and a
320.Em struct msgbuf
321a queue of output buffers for transmission:
322.Bd -literal -offset indent
323struct ibuf {
324	TAILQ_ENTRY(ibuf)	 entry;
325	unsigned char		*buf;
326	size_t			 size;
327	size_t			 max;
328	size_t			 wpos;
329	size_t			 rpos;
330	int			 fd;
331};
332
333struct msgbuf {
334	TAILQ_HEAD(, ibuf)	 bufs;
335	uint32_t		 queued;
336	int			 fd;
337};
338.Ed
339.Pp
340The
341.Fn ibuf_open
342function allocates a fixed-length buffer.
343The buffer may not be resized and may contain a maximum of
344.Fa len
345bytes.
346On success
347.Fn ibuf_open
348returns a pointer to the buffer; on failure it returns NULL.
349.Pp
350.Fn ibuf_dynamic
351allocates a resizeable buffer of initial length
352.Fa len
353and maximum size
354.Fa max .
355Buffers allocated with
356.Fn ibuf_dynamic
357are automatically grown if necessary when data is added.
358.Pp
359.Fn ibuf_add
360is a routine which appends a block of data to
361.Fa buf .
3620 is returned on success and \-1 on failure.
363.Pp
364.Fn ibuf_reserve
365is used to reserve
366.Fa len
367bytes in
368.Fa buf .
369A pointer to the start of the reserved space is returned, or NULL on error.
370.Pp
371.Fn ibuf_seek
372is a function which returns a pointer to the part of the buffer at offset
373.Fa pos
374and of extent
375.Fa len .
376NULL is returned if the requested range is outside the part of the buffer
377in use.
378.Pp
379.Fn ibuf_size
380and
381.Fn ibuf_left
382are functions which return the total bytes used and available in
383.Fa buf
384respectively.
385.Pp
386.Fn ibuf_close
387appends
388.Fa buf
389to
390.Fa msgbuf
391ready to be sent.
392.Pp
393The
394.Fn ibuf_write
395routine transmits as many pending buffers as possible from
396.Fa msgbuf
397using
398.Xr writev 2 .
399It returns 1 if it succeeds, \-1 on error and 0 when no buffers were
400pending or an EOF condition on the socket is detected.
401Temporary resource shortages are returned with errno
402.Er EAGAIN
403and require the application to retry again in the future.
404.Pp
405.Fn ibuf_free
406frees
407.Fa buf
408and any associated storage.
409If
410.Fa buf
411is a NULL pointer, no action occurs.
412.Pp
413The
414.Fn msgbuf_init
415function initializes
416.Fa msgbuf
417so that buffers may be appended to it.
418The
419.Em fd
420member should also be set directly before
421.Fn msgbuf_write
422is used.
423.Pp
424.Fn msgbuf_clear
425empties a msgbuf, removing and discarding any queued buffers.
426.Pp
427The
428.Fn msgbuf_write
429routine calls
430.Xr sendmsg 2
431to transmit buffers queued in
432.Fa msgbuf .
433It returns 1 if it succeeds, \-1 on error, and 0 when the queue was empty
434or an EOF condition on the socket is detected.
435Temporary resource shortages are returned with errno
436.Er EAGAIN
437and require the application to retry again in the future.
438.Pp
439.Fn msgbuf_drain
440discards data from buffers queued in
441.Fa msgbuf
442until
443.Fa n
444bytes have been removed or
445.Fa msgbuf
446is empty.
447.Sh EXAMPLES
448In a typical program, a channel between two processes is created with
449.Xr socketpair 2 ,
450and an
451.Em imsgbuf
452created around one file descriptor in each process:
453.Bd -literal -offset indent
454struct imsgbuf	parent_ibuf, child_ibuf;
455int		imsg_fds[2];
456
457if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_fds) == -1)
458	err(1, "socketpair");
459
460switch (fork()) {
461case -1:
462	err(1, "fork");
463case 0:
464	/* child */
465	close(imsg_fds[0]);
466	imsg_init(&child_ibuf, imsg_fds[1]);
467	exit(child_main(&child_ibuf));
468}
469
470/* parent */
471close(imsg_fds[1]);
472imsg_init(&parent_ibuf, imsg_fds[0]);
473exit(parent_main(&parent_ibuf));
474.Ed
475.Pp
476Messages may then be composed and queued on the
477.Em imsgbuf ,
478for example using the
479.Fn imsg_compose
480function:
481.Bd -literal -offset indent
482enum imsg_type {
483	IMSG_A_MESSAGE,
484	IMSG_MESSAGE2
485};
486
487int
488child_main(struct imsgbuf *ibuf)
489{
490	int	idata;
491	...
492	idata = 42;
493	imsg_compose(ibuf, IMSG_A_MESSAGE,
494	    0, 0, -1, &idata, sizeof idata);
495	...
496}
497.Ed
498.Pp
499A mechanism such as
500.Xr poll 2
501or the
502.Xr event 3
503library is used to monitor the socket file descriptor.
504When the socket is ready for writing, queued messages are transmitted with
505.Fn msgbuf_write :
506.Bd -literal -offset indent
507	if ((n = msgbuf_write(&ibuf-\*(Gtw)) == -1 && errno != EAGAIN) {
508		/* handle write failure */
509	}
510	if (n == 0) {
511		/* handle closed connection */
512	}
513.Ed
514.Pp
515And when ready for reading, messages are first received using
516.Fn imsg_read
517and then extracted with
518.Fn imsg_get :
519.Bd -literal -offset indent
520void
521dispatch_imsg(struct imsgbuf *ibuf)
522{
523	struct imsg	imsg;
524	ssize_t         n, datalen;
525	int		idata;
526
527	if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) {
528		/* handle read error */
529	}
530	if (n == 0) {
531		/* handle closed connection */
532	}
533
534	for (;;) {
535		if ((n = imsg_get(ibuf, &imsg)) == -1) {
536			/* handle read error */
537		}
538		if (n == 0)	/* no more messages */
539			return;
540		datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
541
542		switch (imsg.hdr.type) {
543		case IMSG_A_MESSAGE:
544			if (datalen \*(Lt sizeof idata) {
545				/* handle corrupt message */
546			}
547			memcpy(&idata, imsg.data, sizeof idata);
548			/* handle message received */
549			break;
550		...
551		}
552
553		imsg_free(&imsg);
554	}
555}
556.Ed
557.Sh SEE ALSO
558.Xr socketpair 2 ,
559.Xr unix 4
560