xref: /openbsd-src/lib/libutil/imsg_init.3 (revision 7c0ec4b8992567abb1e1536622dc789a9a39d9f1)
1.\" $OpenBSD: imsg_init.3,v 1.33 2023/12/29 11:48:47 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: December 29 2023 $
19.Dt IMSG_INIT 3
20.Os
21.Sh NAME
22.Nm imsg_init ,
23.Nm imsg_read ,
24.Nm imsg_get ,
25.Nm imsg_get_ibuf ,
26.Nm imsg_get_data ,
27.Nm imsg_get_fd ,
28.Nm imsg_get_id ,
29.Nm imsg_get_len ,
30.Nm imsg_get_pid ,
31.Nm imsg_get_type ,
32.Nm imsg_compose ,
33.Nm imsg_composev ,
34.Nm imsg_compose_ibuf ,
35.Nm imsg_create ,
36.Nm imsg_add ,
37.Nm imsg_close ,
38.Nm imsg_forward ,
39.Nm imsg_free ,
40.Nm imsg_flush ,
41.Nm imsg_clear
42.Nd IPC messaging functions
43.Sh SYNOPSIS
44.In sys/queue.h
45.In imsg.h
46.Ft void
47.Fn imsg_init "struct imsgbuf *imsgbuf" "int fd"
48.Ft ssize_t
49.Fn imsg_read "struct imsgbuf *imsgbuf"
50.Ft ssize_t
51.Fn imsg_get "struct imsgbuf *imsgbuf" "struct imsg *imsg"
52.Ft int
53.Fn imsg_get_ibuf "struct imsg *imsg" "struct ibuf *ibuf"
54.Ft int
55.Fn imsg_get_data "struct imsg *imsg" "void *data" "size_t len"
56.Ft int
57.Fn imsg_get_fd "struct imsg *imsg"
58.Ft uint32_t
59.Fn imsg_get_id "struct imsg *imsg"
60.Ft size_t
61.Fn imsg_get_len "struct imsg *imsg"
62.Ft pid_t
63.Fn imsg_get_pid "struct imsg *imsg"
64.Ft uint32_t
65.Fn imsg_get_type "struct imsg *imsg"
66.Ft int
67.Fn imsg_compose "struct imsgbuf *imsgbuf" "uint32_t type" "uint32_t id" \
68    "pid_t pid" "int fd" "const void *data" "size_t datalen"
69.Ft int
70.Fn imsg_compose_ibuf "struct imsgbuf *imsgbuf" "uint32_t type" \
71    "uint32_t id" "pid_t pid" "struct ibuf *buf"
72.Ft "struct ibuf *"
73.Fn imsg_create "struct imsgbuf *imsgbuf" "uint32_t type" "uint32_t id" \
74    "pid_t pid" "size_t datalen"
75.Ft int
76.Fn imsg_add "struct ibuf *msg" "const void *data" "size_t datalen"
77.Ft void
78.Fn imsg_close "struct imsgbuf *imsgbuf" "struct ibuf *msg"
79.Ft void
80.Fn imsg_free "struct imsg *imsg"
81.Ft int
82.Fn imsg_forward "struct imsgbuf *imsgbuf" "struct imsg *msg"
83.Ft int
84.Fn imsg_flush "struct imsgbuf *imsgbuf"
85.Ft void
86.Fn imsg_clear "struct imsgbuf *imsgbuf"
87.In sys/uio.h
88.Ft int
89.Fn imsg_composev "struct imsgbuf *imsgbuf" "uint32_t type" "uint32_t id" \
90    "pid_t pid" "int fd" "const struct iovec *iov" "int iovcnt"
91.Sh DESCRIPTION
92The
93.Nm imsg
94functions provide a simple mechanism for communication between local processes
95using sockets.
96Each transmitted message is guaranteed to be presented to the receiving program
97whole.
98They are commonly used in privilege separated processes, where processes with
99different rights are required to cooperate.
100.Pp
101A program using these functions should be linked with
102.Em -lutil .
103.Pp
104The basic
105.Nm
106structure is the
107.Em imsgbuf ,
108which wraps a file descriptor and represents one side of a channel on which
109messages are sent and received:
110.Bd -literal -offset indent
111struct imsgbuf {
112	TAILQ_HEAD(, imsg_fd)	fds;
113	struct ibuf_read	r;
114	struct msgbuf		w;
115	int			fd;
116	pid_t			pid;
117};
118.Ed
119.Pp
120.Fn imsg_init
121initializes
122.Fa imsgbuf
123as one side of a channel associated with
124.Fa fd .
125The file descriptor is used to send and receive messages,
126but is not closed by any of the imsg functions.
127An imsgbuf is initialized with the
128.Em w
129member as the output buffer queue,
130.Em fd
131with the file descriptor passed to
132.Fn imsg_init
133and the other members for internal use only.
134.Pp
135The
136.Fn imsg_clear
137function frees any data allocated as part of an imsgbuf.
138.Pp
139.Fn imsg_create ,
140.Fn imsg_add
141and
142.Fn imsg_close
143are generic construction routines for messages that are to be sent using an
144imsgbuf.
145.Pp
146.Fn imsg_create
147creates a new message with header specified by
148.Fa type ,
149.Fa id
150and
151.Fa pid .
152A
153.Fa pid
154of zero uses the process ID returned by
155.Xr getpid 2
156when
157.Fa imsgbuf
158was initialized.
159In addition to this common imsg header,
160.Fa datalen
161bytes of space may be reserved for attaching to this imsg.
162This space is populated using
163.Fn imsg_add .
164.Fn imsg_create
165returns a pointer to a new message if it succeeds, NULL otherwise.
166.Pp
167.Fn imsg_add
168appends to
169.Fa msg
170.Fa datalen
171bytes of ancillary data pointed to by
172.Fa data .
173It returns
174.Fa datalen
175if it succeeds, otherwise
176.Fa msg
177is freed and \-1 is returned.
178.Pp
179.Fn imsg_close
180completes creation of
181.Fa msg
182by adding it to
183.Fa imsgbuf
184output buffer.
185.Pp
186.Fn imsg_compose
187is used to quickly create and queue an imsg.
188It takes the same parameters as the
189.Fn imsg_create ,
190.Fn imsg_add
191and
192.Fn imsg_close
193routines,
194except that only one ancillary data buffer can be provided.
195Additionally, the file descriptor
196.Fa fd
197may be passed over the socket to the other process.
198If
199.Fa fd
200is given, it is closed in the sending program after the message is sent.
201A value of \-1 indicates no file descriptor should be passed.
202This routine returns 1 if it succeeds, \-1 otherwise.
203.Pp
204.Fn imsg_composev
205is similar to
206.Fn imsg_compose .
207It takes the same parameters, except that the ancillary data buffer is specified
208by
209.Fa iovec .
210.Pp
211.Fn imsg_compose_ibuf
212is similar to
213.Fn imsg_compose .
214It takes the same parameters, except that the ancillary data buffer is specified
215by an ibuf
216.Fa buf .
217This routine returns 1 if it succeeds, \-1 otherwise.
218In either case the buffer
219.Fa buf
220is consumed by the function.
221.Pp
222.Fn imsg_forward
223forwards a just received
224.Fa msg
225unaltered on
226.Fa imsgbuf .
227Any attached file descriptor is closed.
228.Pp
229.Fn imsg_flush
230calls
231.Fn msgbuf_write
232in a loop until all imsgs in the output buffer are sent.
233It returns 0 if it succeeds, \-1 otherwise.
234.Pp
235The
236.Fn imsg_read
237routine reads pending data with
238.Xr recvmsg 2
239and queues it as individual messages on
240.Fa imsgbuf .
241It returns the number of bytes read on success, or \-1 on error.
242A return value of \-1 from
243.Fn imsg_read
244invalidates
245.Fa imsgbuf ,
246and renders it suitable only for passing to
247.Fn imsg_clear .
248.Pp
249.Fn imsg_get
250fills in an individual imsg pending on
251.Fa imsgbuf
252into the structure pointed to by
253.Fa imsg .
254It returns the total size of the message, 0 if no messages are ready, or \-1
255for an error.
256Received messages are returned as a
257.Em struct imsg ,
258which must be freed by
259.Fn imsg_free
260when no longer required.
261.Pp
262The accessors
263.Fn imsg_get_type ,
264.Fn imsg_get_pid ,
265.Fn imsg_get_id ,
266and
267.Fn imsg_get_len ,
268return the
269.Fa type ,
270.Fa pid ,
271.Fa id ,
272and payload length used in
273.Fn imsg_create
274to build the
275.Fa imsg .
276If there is no payload
277.Fn imsg_get_len
278returns 0.
279.Pp
280.Fn imsg_get_fd
281returns the file descriptor and passes the responsibility to track the
282descriptor back to the program.
283.Pp
284.Fn imsg_get_data
285and
286.Fn imsg_get_ibuf
287are used to extract the payload of an
288.Fa imsg .
289.Fn imsg_get_data
290can be used if the structure of the payload is known and can be extracted
291in one go.
2920 is returned on success and \-1 on failure.
293.Fn imsg_get_ibuf
294initializes the passed
295.Fa ibuf
296to hold the payload which can be read using
297.Xr ibuf_get 3 .
298The
299.Fa ibuf
300remains valid until
301.Fn imsg_free
302is called and there is no need to call
303.Fn ibuf_free
304on this stack based buffer.
305The function returns 0 on success, \-1 otherwise.
306.Pp
307MAX_IMSGSIZE is defined as the maximum size of a single imsg, currently
30816384 bytes.
309.Sh EXAMPLES
310In a typical program, a channel between two processes is created with
311.Xr socketpair 2 ,
312and an
313.Em imsgbuf
314created around one file descriptor in each process:
315.Bd -literal -offset indent
316struct imsgbuf	parent_ibuf, child_ibuf;
317int		imsg_fds[2];
318
319if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_fds) == -1)
320	err(1, "socketpair");
321
322switch (fork()) {
323case -1:
324	err(1, "fork");
325case 0:
326	/* child */
327	close(imsg_fds[0]);
328	imsg_init(&child_ibuf, imsg_fds[1]);
329	exit(child_main(&child_ibuf));
330}
331
332/* parent */
333close(imsg_fds[1]);
334imsg_init(&parent_ibuf, imsg_fds[0]);
335exit(parent_main(&parent_ibuf));
336.Ed
337.Pp
338Messages may then be composed and queued on the
339.Em imsgbuf ,
340for example using the
341.Fn imsg_compose
342function:
343.Bd -literal -offset indent
344enum imsg_type {
345	IMSG_A_MESSAGE,
346	IMSG_MESSAGE2
347};
348
349int
350child_main(struct imsgbuf *imsgbuf)
351{
352	int	idata;
353	...
354	idata = 42;
355	imsg_compose(imsgbuf, IMSG_A_MESSAGE,
356	    0, 0, -1, &idata, sizeof idata);
357	...
358}
359.Ed
360.Pp
361A mechanism such as
362.Xr poll 2
363or the
364.Xr event 3
365library is used to monitor the socket file descriptor.
366When the socket is ready for writing, queued messages are transmitted with
367.Fn msgbuf_write :
368.Bd -literal -offset indent
369	if ((n = msgbuf_write(&imsgbuf-\*(Gtw)) == -1 && errno != EAGAIN) {
370		/* handle write failure */
371	}
372	if (n == 0) {
373		/* handle closed connection */
374	}
375.Ed
376.Pp
377And when ready for reading, messages are first received using
378.Fn imsg_read
379and then extracted with
380.Fn imsg_get :
381.Bd -literal -offset indent
382void
383dispatch_imsg(struct imsgbuf *imsgbuf)
384{
385	struct imsg	imsg;
386	ssize_t         n;
387	int		idata;
388
389	if ((n = imsg_read(imsgbuf)) == -1 && errno != EAGAIN) {
390		/* handle read error */
391	}
392	if (n == 0) {
393		/* handle closed connection */
394	}
395
396	for (;;) {
397		if ((n = imsg_get(imsgbuf, &imsg)) == -1) {
398			/* handle read error */
399		}
400		if (n == 0)	/* no more messages */
401			return;
402
403		switch (imsg_get_type(&imsg)) {
404		case IMSG_A_MESSAGE:
405			if (imsg_get_data(&imsg, &idata,
406			    sizeof(idata)) == -1) {
407				/* handle corrupt message */
408			}
409			/* handle message received */
410			break;
411		...
412		}
413
414		imsg_free(&imsg);
415	}
416}
417.Ed
418.Sh SEE ALSO
419.Xr socketpair 2 ,
420.Xr ibuf_add 3 ,
421.Xr unix 4
422