xref: /openbsd-src/lib/libutil/imsg_init.3 (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1.\" $OpenBSD: imsg_init.3,v 1.30 2023/09/28 17:00:21 schwarze 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: September 28 2023 $
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_compose_ibuf ,
27.Nm imsg_create ,
28.Nm imsg_add ,
29.Nm imsg_close ,
30.Nm imsg_free ,
31.Nm imsg_flush ,
32.Nm imsg_clear ,
33.Nm ibuf_open ,
34.Nm ibuf_dynamic ,
35.Nm ibuf_add ,
36.Nm ibuf_add_buf ,
37.Nm ibuf_add_n8 ,
38.Nm ibuf_add_n16 ,
39.Nm ibuf_add_n32 ,
40.Nm ibuf_add_n64 ,
41.Nm ibuf_add_zero ,
42.Nm ibuf_reserve ,
43.Nm ibuf_seek ,
44.Nm ibuf_set ,
45.Nm ibuf_set_n8 ,
46.Nm ibuf_set_n16 ,
47.Nm ibuf_set_n32 ,
48.Nm ibuf_set_n64 ,
49.Nm ibuf_data ,
50.Nm ibuf_size ,
51.Nm ibuf_left ,
52.Nm ibuf_close ,
53.Nm ibuf_free ,
54.Nm ibuf_fd_avail ,
55.Nm ibuf_fd_get ,
56.Nm ibuf_fd_set ,
57.Nm ibuf_write ,
58.Nm msgbuf_init ,
59.Nm msgbuf_clear ,
60.Nm msgbuf_write
61.Nd IPC messaging functions
62.Sh SYNOPSIS
63.In sys/types.h
64.In sys/queue.h
65.In sys/uio.h
66.In stdint.h
67.In imsg.h
68.Ft void
69.Fn imsg_init "struct imsgbuf *ibuf" "int fd"
70.Ft ssize_t
71.Fn imsg_read "struct imsgbuf *ibuf"
72.Ft ssize_t
73.Fn imsg_get "struct imsgbuf *ibuf" "struct imsg *imsg"
74.Ft int
75.Fn imsg_compose "struct imsgbuf *ibuf" "uint32_t type" "uint32_t peerid" \
76    "pid_t pid" "int fd" "const void *data" "uint16_t datalen"
77.Ft int
78.Fn imsg_composev "struct imsgbuf *ibuf" "uint32_t type" "uint32_t peerid" \
79    "pid_t pid" "int fd" "const struct iovec *iov" "int iovcnt"
80.Ft int
81.Fn imsg_compose_ibuf "struct imsgbuf *ibuf" "uint32_t type" "uint32_t peerid" \
82    "pid_t pid" "struct ibuf *buf"
83.Ft "struct ibuf *"
84.Fn imsg_create "struct imsgbuf *ibuf" "uint32_t type" "uint32_t peerid" \
85    "pid_t pid" "uint16_t datalen"
86.Ft int
87.Fn imsg_add "struct ibuf *msg" "const void *data" "uint16_t datalen"
88.Ft void
89.Fn imsg_close "struct imsgbuf *ibuf" "struct ibuf *msg"
90.Ft void
91.Fn imsg_free "struct imsg *imsg"
92.Ft int
93.Fn imsg_flush "struct imsgbuf *ibuf"
94.Ft void
95.Fn imsg_clear "struct imsgbuf *ibuf"
96.Ft "struct ibuf *"
97.Fn ibuf_open "size_t len"
98.Ft "struct ibuf *"
99.Fn ibuf_dynamic "size_t len" "size_t max"
100.Ft int
101.Fn ibuf_add "struct ibuf *buf" "const void *data" "size_t len"
102.Ft int
103.Fn ibuf_add_buf "struct ibuf *buf" "const struct ibuf *from"
104.Ft int
105.Fn ibuf_add_n8 "struct ibuf *buf" "uint64_t value"
106.Ft int
107.Fn ibuf_add_n16 "struct ibuf *buf" "uint64_t value"
108.Ft int
109.Fn ibuf_add_n32 "struct ibuf *buf" "uint64_t value"
110.Ft int
111.Fn ibuf_add_n64 "struct ibuf *buf" "uint64_t value"
112.Ft int
113.Fn ibuf_add_zero "struct ibuf *buf" "size_t len"
114.Ft "void *"
115.Fn ibuf_reserve "struct ibuf *buf" "size_t len"
116.Ft "void *"
117.Fn ibuf_seek "struct ibuf *buf" "size_t pos" "size_t len"
118.Ft int
119.Fn ibuf_set "struct ibuf *buf" "size_t pos" "const void *data" \
120    "size_t len"
121.Ft int
122.Fn ibuf_set_n8 "struct ibuf *buf" "size_t pos" "uint64_t value"
123.Ft int
124.Fn ibuf_set_n16 "struct ibuf *buf" "size_t pos" "uint64_t value"
125.Ft int
126.Fn ibuf_set_n32 "struct ibuf *buf" "size_t pos" "uint64_t value"
127.Ft int
128.Fn ibuf_set_n64 "struct ibuf *buf" "size_t pos" "uint64_t value"
129.Ft "void *"
130.Fn ibuf_data "struct ibuf *buf"
131.Ft size_t
132.Fn ibuf_size "struct ibuf *buf"
133.Ft size_t
134.Fn ibuf_left "struct ibuf *buf"
135.Ft void
136.Fn ibuf_close "struct msgbuf *msgbuf" "struct ibuf *buf"
137.Ft void
138.Fn ibuf_free "struct ibuf *buf"
139.Ft int
140.Fn ibuf_fd_avail "struct ibuf *buf"
141.Ft int
142.Fn ibuf_fd_get "struct ibuf *buf"
143.Ft void
144.Fn ibuf_fd_set "struct ibuf *buf" "int fd"
145.Ft int
146.Fn ibuf_write "struct msgbuf *msgbuf"
147.Ft void
148.Fn msgbuf_init "struct msgbuf *msgbuf"
149.Ft void
150.Fn msgbuf_clear "struct msgbuf *msgbuf"
151.Ft int
152.Fn msgbuf_write "struct msgbuf *msgbuf"
153.Sh DESCRIPTION
154The
155.Nm imsg
156functions provide a simple mechanism for communication between local processes
157using sockets.
158Each transmitted message is guaranteed to be presented to the receiving program
159whole.
160They are commonly used in privilege separated processes, where processes with
161different rights are required to cooperate.
162.Pp
163A program using these functions should be linked with
164.Em -lutil .
165.Pp
166The basic
167.Nm
168structure is the
169.Em imsgbuf ,
170which wraps a file descriptor and represents one side of a channel on which
171messages are sent and received:
172.Bd -literal -offset indent
173struct imsgbuf {
174	TAILQ_HEAD(, imsg_fd)	fds;
175	struct ibuf_read	r;
176	struct msgbuf		w;
177	int			fd;
178	pid_t			pid;
179};
180.Ed
181.Pp
182.Fn imsg_init
183initializes
184.Fa ibuf
185as one side of a channel associated with
186.Fa fd .
187The file descriptor is used to send and receive messages,
188but is not closed by any of the imsg functions.
189An imsgbuf is initialized with the
190.Em w
191member as the output buffer queue,
192.Em fd
193with the file descriptor passed to
194.Fn imsg_init
195and the other members for internal use only.
196.Pp
197The
198.Fn imsg_clear
199function frees any data allocated as part of an imsgbuf.
200.Pp
201.Fn imsg_create ,
202.Fn imsg_add
203and
204.Fn imsg_close
205are generic construction routines for messages that are to be sent using an
206imsgbuf.
207.Pp
208.Fn imsg_create
209creates a new message with header specified by
210.Fa type ,
211.Fa peerid
212and
213.Fa pid .
214A
215.Fa pid
216of zero uses the process ID returned by
217.Xr getpid 2
218when
219.Fa ibuf
220was initialized.
221In addition to this common imsg header,
222.Fa datalen
223bytes of space may be reserved for attaching to this imsg.
224This space is populated using
225.Fn imsg_add .
226.Fn imsg_create
227returns a pointer to a new message if it succeeds, NULL otherwise.
228.Pp
229.Fn imsg_add
230appends to
231.Fa msg
232.Fa datalen
233bytes of ancillary data pointed to by
234.Fa data .
235It returns
236.Fa datalen
237if it succeeds, otherwise
238.Fa msg
239is freed and \-1 is returned.
240.Pp
241.Fn imsg_close
242completes creation of
243.Fa msg
244by adding it to
245.Fa ibuf
246output buffer.
247.Pp
248.Fn imsg_compose
249is used to quickly create and queue an imsg.
250It takes the same parameters as the
251.Fn imsg_create ,
252.Fn imsg_add
253and
254.Fn imsg_close
255routines,
256except that only one ancillary data buffer can be provided.
257Additionally, the file descriptor
258.Fa fd
259may be passed over the socket to the other process.
260If
261.Fa fd
262is given, it is closed in the sending program after the message is sent.
263A value of \-1 indicates no file descriptor should be passed.
264This routine returns 1 if it succeeds, \-1 otherwise.
265.Pp
266.Fn imsg_composev
267is similar to
268.Fn imsg_compose .
269It takes the same parameters, except that the ancillary data buffer is specified
270by
271.Fa iovec .
272.Pp
273.Fn imsg_compose_ibuf
274is similar to
275.Fn imsg_compose .
276It takes the same parameters, except that the ancillary data buffer is specified
277by an ibuf
278.Fa buf .
279This routine returns 1 if it succeeds, \-1 otherwise.
280In either case the buffer
281.Fa buf
282is consumed by the function.
283.Pp
284.Fn imsg_flush
285calls
286.Fn msgbuf_write
287in a loop until all imsgs in the output buffer are sent.
288It returns 0 if it succeeds, \-1 otherwise.
289.Pp
290The
291.Fn imsg_read
292routine reads pending data with
293.Xr recvmsg 2
294and queues it as individual messages on
295.Fa imsgbuf .
296It returns the number of bytes read on success, or \-1 on error.
297A return value of \-1 from
298.Fn imsg_read
299invalidates
300.Fa imsgbuf ,
301and renders it suitable only for passing to
302.Fn imsg_clear .
303.Pp
304.Fn imsg_get
305fills in an individual imsg pending on
306.Fa imsgbuf
307into the structure pointed to by
308.Fa imsg .
309It returns the total size of the message, 0 if no messages are ready, or \-1
310for an error.
311Received messages are returned as a
312.Em struct imsg ,
313which must be freed by
314.Fn imsg_free
315when no longer required.
316.Em struct imsg
317has this form:
318.Bd -literal -offset indent
319struct imsg {
320	struct imsg_hdr	 hdr;
321	int		 fd;
322	void		*data;
323};
324
325struct imsg_hdr {
326	uint32_t	 type;
327	uint16_t	 len;
328	uint16_t	 flags;
329	uint32_t	 peerid;
330	uint32_t	 pid;
331};
332.Ed
333.Pp
334The header members are:
335.Bl -tag -width Ds -offset indent
336.It type
337A integer identifier, typically used to express the meaning of the message.
338.It len
339The total length of the imsg, including the header and any ancillary data
340transmitted with the message (pointed to by the
341.Em data
342member of the message itself).
343.It flags
344Flags used internally by the imsg functions: should not be used by application
345programs.
346.It peerid, pid
34732-bit values specified on message creation and free for any use by the
348caller, normally used to identify the message sender.
349.El
350.Pp
351In addition,
352.Em struct imsg
353has the following:
354.Bl -tag -width Ds -offset indent
355.It fd
356The file descriptor specified when the message was created and passed using the
357socket control message API, or \-1 if no file descriptor was sent.
358.It data
359A pointer to the ancillary data transmitted with the imsg.
360.El
361.Pp
362The IMSG_HEADER_SIZE define is the size of the imsg message header, which
363may be subtracted from the
364.Fa len
365member of
366.Em struct imsg_hdr
367to obtain the length of any additional data passed with the message.
368.Pp
369MAX_IMSGSIZE is defined as the maximum size of a single imsg, currently
37016384 bytes.
371.Sh BUFFERS
372The imsg API defines functions to manipulate buffers, used internally and during
373construction of imsgs with
374.Fn imsg_create .
375A
376.Em struct ibuf
377is a single buffer and a
378.Em struct msgbuf
379a queue of output buffers for transmission:
380.Bd -literal -offset indent
381struct ibuf {
382	TAILQ_ENTRY(ibuf)	 entry;
383	unsigned char		*buf;
384	size_t			 size;
385	size_t			 max;
386	size_t			 wpos;
387	size_t			 rpos;
388	int			 fd;
389};
390
391struct msgbuf {
392	TAILQ_HEAD(, ibuf)	 bufs;
393	uint32_t		 queued;
394	int			 fd;
395};
396.Ed
397.Pp
398The
399.Fn ibuf_open
400function allocates a fixed-length buffer.
401The buffer may not be resized and may contain a maximum of
402.Fa len
403bytes.
404On success
405.Fn ibuf_open
406returns a pointer to the buffer; on failure it returns NULL.
407.Pp
408.Fn ibuf_dynamic
409allocates a resizeable buffer of initial length
410.Fa len
411and maximum size
412.Fa max .
413Buffers allocated with
414.Fn ibuf_dynamic
415are automatically grown if necessary when data is added.
416.Pp
417.Fn ibuf_add
418appends a block of data to
419.Fa buf .
4200 is returned on success and \-1 on failure.
421.Pp
422.Fn ibuf_add_buf
423appends the buffer
424.Fa from
425to
426.Fa buf .
4270 is returned on success and \-1 on failure.
428.Pp
429.Fn ibuf_add_n8 ,
430.Fn ibuf_add_n16 ,
431.Fn ibuf_add_n32 ,
432and
433.Fn ibuf_add_n64
434add a 1-byte, 2-byte, 4-byte, and 8-byte
435.Fa value
436to
437.Fa buf
438in network byte order.
439This function checks
440.Fa value
441to not overflow.
4420 is returned on success and \-1 on failure.
443.Pp
444.Fn ibuf_add_zero
445appends a block of zeros to
446.Fa buf .
4470 is returned on success and \-1 on failure.
448.Pp
449.Fn ibuf_reserve
450is used to reserve
451.Fa len
452bytes in
453.Fa buf .
454A pointer to the start of the reserved space is returned, or NULL on error.
455.Pp
456.Fn ibuf_seek
457returns a pointer to the part of the buffer at offset
458.Fa pos
459and of extent
460.Fa len .
461NULL is returned if the requested range is outside the part of the buffer
462in use.
463.Pp
464.Fn ibuf_set
465replaces a part of
466.Fa buf
467at offset
468.Fa pos
469with the
470.Fa data
471of extent
472.Fa len .
4730 is returned on success and \-1 on failure.
474.Pp
475.Fn ibuf_set_n8 ,
476.Fn ibuf_set_n16 ,
477.Fn ibuf_set_n32
478and
479.Fn ibuf_set_n64
480replace a 1-byte, 2-byte, 4-byte or 8-byte
481.Fa value
482at offset
483.Fa pos
484in the buffer
485.Fa buf
486in network byte order.
487This function checks
488.Fa value
489to not overflow.
4900 is returned on success and \-1 on failure.
491.Pp
492.Fn ibuf_data
493returns the pointer to the internal buffer.
494This function should only be used together with
495.Fn ibuf_size
496to process a previously generated buffer.
497.Pp
498.Fn ibuf_size
499and
500.Fn ibuf_left
501are functions which return the total bytes used and available in
502.Fa buf
503respectively.
504.Pp
505.Fn ibuf_close
506appends
507.Fa buf
508to
509.Fa msgbuf
510ready to be sent.
511.Pp
512.Fn ibuf_fd_avail ,
513.Fn ibuf_fd_get
514and
515.Fn ibuf_fd_set
516are functions to check, get and set the file descriptor assigned to
517.Fa buf .
518After calling
519.Fn ibuf_fd_set
520the file descriptor is part of the
521.Fa buf
522and will be transmitted or closed by the ibuf API.
523Any previously set file descriptor will be closed before assigning a
524new descriptor.
525.Fn ibuf_fd_get
526returns the file descriptor and passes the responsibility to track the
527descriptor back to the program.
528.Fn ibuf_fd_avail
529returns true if there is a file descriptor set on
530.Fa buf .
531.Pp
532.Fn ibuf_free
533frees
534.Fa buf
535and any associated storage, and closes any file descriptor set with
536.Fn ibuf_fd_set .
537If
538.Fa buf
539is a NULL pointer, no action occurs.
540.Pp
541The
542.Fn ibuf_write
543routine transmits as many pending buffers as possible from
544.Fa msgbuf
545using
546.Xr writev 2 .
547It returns 1 if it succeeds, \-1 on error and 0 when no buffers were
548pending or an EOF condition on the socket is detected.
549Temporary resource shortages are returned with errno
550.Er EAGAIN
551and require the application to retry again in the future.
552.Pp
553The
554.Fn msgbuf_init
555function initializes
556.Fa msgbuf
557so that buffers may be appended to it.
558The
559.Em fd
560member should also be set directly before
561.Fn msgbuf_write
562is used.
563.Pp
564.Fn msgbuf_clear
565empties a msgbuf, removing and discarding any queued buffers.
566.Pp
567The
568.Fn msgbuf_write
569routine calls
570.Xr sendmsg 2
571to transmit buffers queued in
572.Fa msgbuf .
573It returns 1 if it succeeds, \-1 on error, and 0 when the queue was empty
574or an EOF condition on the socket is detected.
575Temporary resource shortages are returned with errno
576.Er EAGAIN
577and require the application to retry again in the future.
578.Sh EXAMPLES
579In a typical program, a channel between two processes is created with
580.Xr socketpair 2 ,
581and an
582.Em imsgbuf
583created around one file descriptor in each process:
584.Bd -literal -offset indent
585struct imsgbuf	parent_ibuf, child_ibuf;
586int		imsg_fds[2];
587
588if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_fds) == -1)
589	err(1, "socketpair");
590
591switch (fork()) {
592case -1:
593	err(1, "fork");
594case 0:
595	/* child */
596	close(imsg_fds[0]);
597	imsg_init(&child_ibuf, imsg_fds[1]);
598	exit(child_main(&child_ibuf));
599}
600
601/* parent */
602close(imsg_fds[1]);
603imsg_init(&parent_ibuf, imsg_fds[0]);
604exit(parent_main(&parent_ibuf));
605.Ed
606.Pp
607Messages may then be composed and queued on the
608.Em imsgbuf ,
609for example using the
610.Fn imsg_compose
611function:
612.Bd -literal -offset indent
613enum imsg_type {
614	IMSG_A_MESSAGE,
615	IMSG_MESSAGE2
616};
617
618int
619child_main(struct imsgbuf *ibuf)
620{
621	int	idata;
622	...
623	idata = 42;
624	imsg_compose(ibuf, IMSG_A_MESSAGE,
625	    0, 0, -1, &idata, sizeof idata);
626	...
627}
628.Ed
629.Pp
630A mechanism such as
631.Xr poll 2
632or the
633.Xr event 3
634library is used to monitor the socket file descriptor.
635When the socket is ready for writing, queued messages are transmitted with
636.Fn msgbuf_write :
637.Bd -literal -offset indent
638	if ((n = msgbuf_write(&ibuf-\*(Gtw)) == -1 && errno != EAGAIN) {
639		/* handle write failure */
640	}
641	if (n == 0) {
642		/* handle closed connection */
643	}
644.Ed
645.Pp
646And when ready for reading, messages are first received using
647.Fn imsg_read
648and then extracted with
649.Fn imsg_get :
650.Bd -literal -offset indent
651void
652dispatch_imsg(struct imsgbuf *ibuf)
653{
654	struct imsg	imsg;
655	ssize_t         n, datalen;
656	int		idata;
657
658	if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) {
659		/* handle read error */
660	}
661	if (n == 0) {
662		/* handle closed connection */
663	}
664
665	for (;;) {
666		if ((n = imsg_get(ibuf, &imsg)) == -1) {
667			/* handle read error */
668		}
669		if (n == 0)	/* no more messages */
670			return;
671		datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
672
673		switch (imsg.hdr.type) {
674		case IMSG_A_MESSAGE:
675			if (datalen \*(Lt sizeof idata) {
676				/* handle corrupt message */
677			}
678			memcpy(&idata, imsg.data, sizeof idata);
679			/* handle message received */
680			break;
681		...
682		}
683
684		imsg_free(&imsg);
685	}
686}
687.Ed
688.Sh SEE ALSO
689.Xr socketpair 2 ,
690.Xr unix 4
691