xref: /openbsd-src/lib/libutil/imsg_init.3 (revision ff59764deb7c720c75d582b75dac4b924ec7c8a6)
1.\" $OpenBSD: imsg_init.3,v 1.41 2024/11/26 13:57:31 claudio Exp $
2.\"
3.\" Copyright (c) 2023 Claudio Jeker <claudio@openbsd.org>
4.\" Copyright (c) 2010 Nicholas Marriott <nicm@openbsd.org>
5.\"
6.\" Permission to use, copy, modify, and distribute this software for any
7.\" purpose with or without fee is hereby granted, provided that the above
8.\" copyright notice and this permission notice appear in all copies.
9.\"
10.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14.\" WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15.\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16.\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17.\"
18.Dd $Mdocdate: November 26 2024 $
19.Dt IMSG_ADD 3
20.Os
21.Sh NAME
22.Nm imsg_add ,
23.Nm imsg_close ,
24.Nm imsg_compose ,
25.Nm imsg_compose_ibuf ,
26.Nm imsg_composev ,
27.Nm imsg_create ,
28.Nm imsg_forward ,
29.Nm imsg_free ,
30.Nm imsg_get ,
31.Nm imsg_get_data ,
32.Nm imsg_get_fd ,
33.Nm imsg_get_ibuf ,
34.Nm imsg_get_id ,
35.Nm imsg_get_ibuf ,
36.Nm imsg_get_len ,
37.Nm imsg_get_pid ,
38.Nm imsg_get_type ,
39.Nm imsgbuf_allow_fdpass ,
40.Nm imsgbuf_clear ,
41.Nm imsgbuf_flush ,
42.Nm imsgbuf_init ,
43.Nm imsgbuf_queuelen ,
44.Nm imsgbuf_read ,
45.Nm imsgbuf_set_maxsize ,
46.Nm imsgbuf_write
47.Nd IPC messaging functions
48.Sh SYNOPSIS
49.In sys/queue.h
50.In imsg.h
51.Fd #define IMSG_HEADER_SIZE sizeof(struct imsg_hdr)
52.Fd #define MAX_IMSGSIZE 16384
53.Ft int
54.Fn imsg_add "struct ibuf *msg" "const void *data" "size_t datalen"
55.Ft void
56.Fn imsg_close "struct imsgbuf *imsgbuf" "struct ibuf *msg"
57.Ft int
58.Fn imsg_compose "struct imsgbuf *imsgbuf" "uint32_t type" "uint32_t id" \
59    "pid_t pid" "int fd" "const void *data" "size_t datalen"
60.Ft int
61.Fn imsg_compose_ibuf "struct imsgbuf *imsgbuf" "uint32_t type" \
62    "uint32_t id" "pid_t pid" "struct ibuf *buf"
63.Ft "struct ibuf *"
64.Fn imsg_create "struct imsgbuf *imsgbuf" "uint32_t type" "uint32_t id" \
65    "pid_t pid" "size_t datalen"
66.Ft int
67.Fn imsg_forward "struct imsgbuf *imsgbuf" "struct imsg *msg"
68.Ft void
69.Fn imsg_free "struct imsg *imsg"
70.Ft ssize_t
71.Fn imsg_get "struct imsgbuf *imsgbuf" "struct imsg *imsg"
72.Ft int
73.Fn imsg_get_data "struct imsg *imsg" "void *data" "size_t len"
74.Ft int
75.Fn imsg_get_fd "struct imsg *imsg"
76.Ft int
77.Fn imsg_get_ibuf "struct imsg *imsg" "struct ibuf *ibuf"
78.Ft uint32_t
79.Fn imsg_get_id "struct imsg *imsg"
80.Ft size_t
81.Fn imsg_get_len "struct imsg *imsg"
82.Ft pid_t
83.Fn imsg_get_pid "struct imsg *imsg"
84.Ft uint32_t
85.Fn imsg_get_type "struct imsg *imsg"
86.Ft void
87.Fn imsgbuf_allow_fdpass "struct imsgbuf *imsgbuf"
88.Ft void
89.Fn imsgbuf_clear "struct imsgbuf *imsgbuf"
90.Ft int
91.Fn imsgbuf_flush "struct imsgbuf *imsgbuf"
92.Ft int
93.Fn imsgbuf_init "struct imsgbuf *imsgbuf" "int fd"
94.Ft uint32_t
95.Fn imsgbuf_queuelen "struct imsgbuf *imsgbuf"
96.Ft int
97.Fn imsgbuf_read "struct imsgbuf *imsgbuf"
98.Ft int
99.Fn imsgbuf_set_maxsize "struct imsgbuf *imsgbuf" "uint32_t maxsize"
100.Ft int
101.Fn imsgbuf_write "struct imsgbuf *imsgbuf"
102.In sys/uio.h
103.Ft int
104.Fn imsg_composev "struct imsgbuf *imsgbuf" "uint32_t type" "uint32_t id" \
105    "pid_t pid" "int fd" "const struct iovec *iov" "int iovcnt"
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
119.Fn imsgbuf_init
120initializes
121.Fa imsgbuf
122as one side of a channel associated with
123.Fa fd .
124The file descriptor is used to send and receive messages,
125but is not closed by any of the imsg functions.
126It returns 0 if successful and -1 on failure.
127.Pp
128.Fn imsgbuf_allow_fdpass
129enables file descriptor passing in both directions for this
130.Fa imsgbuf .
131.Pp
132.Fn imsgbuf_set_maxsize
133changes the default maximum imsg size from
134.Dv MAX_IMSGSIZE
135to
136.Fa maxsize .
137.Fa maxsize
138must be bigger than
139.Dv IMSG_HEADER_SIZE .
140It returns 0 if successful and -1 on failure.
141.Pp
142The
143.Fn imsgbuf_clear
144function frees any data allocated as part of an imsgbuf.
145This function does not close the file descriptor used for communication.
146.Pp
147The
148.Fn imsgbuf_read
149routine reads pending data with
150.Xr recvmsg 2
151and queues it as individual messages on
152.Fa imsgbuf .
153It returns 1 on success, 0 if the connection is closed, or \-1 on error
154and the global variable
155.Va errno
156is set to indicate the error.
157The errors
158.Er EINTR
159and
160.Er EAGAIN
161are treated as follows.
162.Er EINTR
163will automatically retry the read operation while the other errors are
164ignored with a 1 return.
165.Pp
166.Fn imsgbuf_write
167writes out queued messages.
168It returns 0 if it succeeds, -1 on error and the global variable
169.Va errno
170is set to indicate the error.
171The errors
172.Er EINTR ,
173.Er EAGAIN ,
174and
175.Er ENOBUFS
176are treated as follows.
177.Er EINTR
178will automatically retry the write operation while the other errors are
179ignored with a 0 return.
180.Pp
181.Fn imsgbuf_flush
182calls
183.Fn imsgbuf_write
184in a loop until all imsgs in the output buffer are sent.
185It returns 0 if it succeeds, \-1 otherwise and the global variable
186.Va errno
187is set to indicate the error.
188.Fn imsgbuf_flush
189should not be called on non-blocking sockets since it will busy loop if the
190socket is not available.
191.Pp
192.Fn imsgbuf_queuelen
193returns the number of messages ready to be sent.
194This function returns 0 if no messages are pending for transmission.
195.Pp
196.Fn imsg_create ,
197.Fn imsg_add
198and
199.Fn imsg_close
200are generic construction routines for messages that are to be sent using an
201imsgbuf.
202.Pp
203.Fn imsg_create
204creates a new message with header specified by
205.Fa type ,
206.Fa id
207and
208.Fa pid .
209A
210.Fa pid
211of zero uses the process ID returned by
212.Xr getpid 2
213when
214.Fa imsgbuf
215was initialized.
216In addition to this common imsg header,
217.Fa datalen
218bytes of space may be reserved for attaching to this imsg.
219This space is populated using
220.Fn imsg_add .
221.Fn imsg_create
222returns a pointer to a new message if it succeeds, NULL otherwise.
223.Pp
224.Fn imsg_add
225appends to
226.Fa msg
227.Fa datalen
228bytes of ancillary data pointed to by
229.Fa data .
230It returns
231.Fa datalen
232if it succeeds, otherwise
233.Fa msg
234is freed and \-1 is returned.
235.Pp
236.Fn imsg_close
237completes creation of
238.Fa msg
239by adding it to
240.Fa imsgbuf
241output buffer.
242.Pp
243.Fn imsg_compose
244is used to quickly create and queue an imsg.
245It takes the same parameters as the
246.Fn imsg_create ,
247.Fn imsg_add
248and
249.Fn imsg_close
250routines,
251except that only one ancillary data buffer can be provided.
252Additionally, the file descriptor
253.Fa fd
254may be passed over the socket to the other process.
255If
256.Fa fd
257is given, it is closed in the sending program after the message is sent.
258A value of \-1 indicates no file descriptor should be passed.
259This routine returns 1 if it succeeds, \-1 otherwise.
260.Pp
261.Fn imsg_composev
262is similar to
263.Fn imsg_compose .
264It takes the same parameters, except that the ancillary data buffer is specified
265by
266.Fa iovec .
267.Pp
268.Fn imsg_compose_ibuf
269is similar to
270.Fn imsg_compose .
271It takes the same parameters, except that the ancillary data buffer is specified
272by an ibuf
273.Fa buf .
274This routine returns 1 if it succeeds, \-1 otherwise.
275In either case the buffer
276.Fa buf
277is consumed by the function.
278.Pp
279.Fn imsg_forward
280forwards a just received
281.Fa msg
282unaltered on
283.Fa imsgbuf .
284File descriptors are not forwarded by this function.
285It is possible to call
286.Fn imsg_forward
287more than once per message.
288.Pp
289.Fn imsg_get
290fills in an individual imsg pending on
291.Fa imsgbuf
292into the structure pointed to by
293.Fa imsg .
294It returns the total size of the message, 0 if no messages are ready, or \-1
295for an error.
296Received messages are returned as a
297.Em struct imsg ,
298which must be freed by
299.Fn imsg_free
300when no longer required.
301.Pp
302The accessors
303.Fn imsg_get_type ,
304.Fn imsg_get_pid ,
305.Fn imsg_get_id ,
306and
307.Fn imsg_get_len ,
308return the
309.Fa type ,
310.Fa pid ,
311.Fa id ,
312and payload length used in
313.Fn imsg_create
314to build the
315.Fa imsg .
316If there is no payload
317.Fn imsg_get_len
318returns 0.
319.Pp
320.Fn imsg_get_fd
321returns the file descriptor and passes the responsibility to track the
322descriptor back to the program.
323Unclaimed file descriptors are closed by
324.Fn imsg_free .
325.Pp
326.Fn imsg_get_data
327and
328.Fn imsg_get_ibuf
329are used to extract the payload of an
330.Fa imsg .
331.Fn imsg_get_data
332can be used if the structure of the payload is known and can be extracted
333in one go.
3340 is returned on success and \-1 on failure.
335.Fn imsg_get_ibuf
336initializes the passed
337.Fa ibuf
338to hold the payload which can be read using
339.Xr ibuf_get 3 .
340The
341.Fa ibuf
342remains valid until
343.Fn imsg_free
344is called and there is no need to call
345.Fn ibuf_free
346on this stack based buffer.
347The function returns 0 on success, \-1 otherwise.
348.Pp
349MAX_IMSGSIZE is defined as the maximum size of a single imsg, currently
35016384 bytes.
351.Sh EXAMPLES
352In a typical program, a channel between two processes is created with
353.Xr socketpair 2 ,
354and an
355.Em imsgbuf
356created around one file descriptor in each process:
357.Bd -literal -offset indent
358struct imsgbuf	parent_ibuf, child_ibuf;
359int		imsg_fds[2];
360
361if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_fds) == -1)
362	err(1, "socketpair");
363
364switch (fork()) {
365case -1:
366	err(1, "fork");
367case 0:
368	/* child */
369	close(imsg_fds[0]);
370	if (imsgbuf_init(&child_ibuf, imsg_fds[1]) == -1)
371		err(1, NULL);
372	exit(child_main(&child_ibuf));
373}
374
375/* parent */
376close(imsg_fds[1]);
377if (imsgbuf_init(&parent_ibuf, imsg_fds[0]) == -1)
378	err(1, NULL);
379exit(parent_main(&parent_ibuf));
380.Ed
381.Pp
382Messages may then be composed and queued on the
383.Em imsgbuf ,
384for example using the
385.Fn imsg_compose
386function:
387.Bd -literal -offset indent
388enum imsg_type {
389	IMSG_A_MESSAGE,
390	IMSG_MESSAGE2
391};
392
393int
394child_main(struct imsgbuf *imsgbuf)
395{
396	int	idata;
397	...
398	idata = 42;
399	imsg_compose(imsgbuf, IMSG_A_MESSAGE,
400	    0, 0, -1, &idata, sizeof idata);
401	...
402}
403.Ed
404.Pp
405A mechanism such as
406.Xr poll 2
407or the
408.Xr event 3
409library is used to monitor the socket file descriptor.
410When the socket is ready for writing, queued messages are transmitted with
411.Fn imsgbuf_write :
412.Bd -literal -offset indent
413	if (imsgbuf_write(imsgbuf) == -1) {
414		if (errno == EPIPE)
415			/* handle closed connection */
416		else
417			/* handle write failure */
418	}
419.Ed
420.Pp
421And when ready for reading, messages are first received using
422.Fn imsgbuf_read
423and then extracted with
424.Fn imsg_get :
425.Bd -literal -offset indent
426void
427dispatch_imsg(struct imsgbuf *imsgbuf)
428{
429	struct imsg	imsg;
430	ssize_t         n;
431	int		idata;
432
433	switch (imsgbuf_read(imsgbuf)) {
434	case -1:
435		/* handle read error */
436		break;
437	case 0:
438		/* handle closed connection */
439		break;
440	}
441
442	for (;;) {
443		if ((n = imsg_get(imsgbuf, &imsg)) == -1) {
444			/* handle read error */
445		}
446		if (n == 0)	/* no more messages */
447			return;
448
449		switch (imsg_get_type(&imsg)) {
450		case IMSG_A_MESSAGE:
451			if (imsg_get_data(&imsg, &idata,
452			    sizeof(idata)) == -1) {
453				/* handle corrupt message */
454			}
455			/* handle message received */
456			break;
457		...
458		}
459
460		imsg_free(&imsg);
461	}
462}
463.Ed
464.Sh SEE ALSO
465.Xr socketpair 2 ,
466.Xr ibuf_add 3 ,
467.Xr unix 4
468