xref: /openbsd-src/lib/libutil/imsg_init.3 (revision 521ba2f2ab0e0e89d1776559874b3ecc227442fc)
1.\" $OpenBSD: imsg_init.3,v 1.28 2023/06/20 06:53:29 jsg 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: June 20 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 data of extent
470.Fa len .
4710 is returned on success and \-1 on failure.
472.Pp
473.Fn ibuf_set_n8 ,
474.Fn ibuf_set_n16 ,
475.Fn ibuf_seek_set_n32
476and
477.Fn ibuf_seek_set_n64
478replace a 1-byte, 2-byte, 4-byte or 8-byte
479.Fa value
480at offset
481.Fa pos
482in the buffer
483.Fa buf
484in network byte order.
485This function checks
486.Fa value
487to not overflow.
4880 is returned on success and \-1 on failure.
489.Pp
490.Fn ibuf_data
491returns the pointer to the internal buffer.
492This function should only be used together with
493.Fn ibuf_size
494to process a previously generated buffer.
495.Pp
496.Fn ibuf_size
497and
498.Fn ibuf_left
499are functions which return the total bytes used and available in
500.Fa buf
501respectively.
502.Pp
503.Fn ibuf_close
504appends
505.Fa buf
506to
507.Fa msgbuf
508ready to be sent.
509.Pp
510.Fn ibuf_fd_avail ,
511.Fn ibuf_fd_get
512and
513.Fn ibuf_fd_set
514are functions to check, get and set the file descriptor assigned to
515.Fa buf .
516After calling
517.Fn ibuf_fd_set
518the file descriptor is part of the
519.Fa buf
520and will be transmitted or closed by the ibuf API.
521Any previously set file descriptor will be closed before assigning a
522new descriptor.
523.Fn ibuf_fd_get
524returns the file descriptor and passes the responsibility to track the
525descriptor back to the program.
526.Fn ibuf_fd_avail
527returns true if there is a file descriptor set on
528.Fa buf .
529.Pp
530.Fn ibuf_free
531frees
532.Fa buf
533and any associated storage, and closes any file descriptor set with
534.Fn ibuf_fd_set .
535If
536.Fa buf
537is a NULL pointer, no action occurs.
538.Pp
539The
540.Fn ibuf_write
541routine transmits as many pending buffers as possible from
542.Fa msgbuf
543using
544.Xr writev 2 .
545It returns 1 if it succeeds, \-1 on error and 0 when no buffers were
546pending or an EOF condition on the socket is detected.
547Temporary resource shortages are returned with errno
548.Er EAGAIN
549and require the application to retry again in the future.
550.Pp
551The
552.Fn msgbuf_init
553function initializes
554.Fa msgbuf
555so that buffers may be appended to it.
556The
557.Em fd
558member should also be set directly before
559.Fn msgbuf_write
560is used.
561.Pp
562.Fn msgbuf_clear
563empties a msgbuf, removing and discarding any queued buffers.
564.Pp
565The
566.Fn msgbuf_write
567routine calls
568.Xr sendmsg 2
569to transmit buffers queued in
570.Fa msgbuf .
571It returns 1 if it succeeds, \-1 on error, and 0 when the queue was empty
572or an EOF condition on the socket is detected.
573Temporary resource shortages are returned with errno
574.Er EAGAIN
575and require the application to retry again in the future.
576.Sh EXAMPLES
577In a typical program, a channel between two processes is created with
578.Xr socketpair 2 ,
579and an
580.Em imsgbuf
581created around one file descriptor in each process:
582.Bd -literal -offset indent
583struct imsgbuf	parent_ibuf, child_ibuf;
584int		imsg_fds[2];
585
586if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_fds) == -1)
587	err(1, "socketpair");
588
589switch (fork()) {
590case -1:
591	err(1, "fork");
592case 0:
593	/* child */
594	close(imsg_fds[0]);
595	imsg_init(&child_ibuf, imsg_fds[1]);
596	exit(child_main(&child_ibuf));
597}
598
599/* parent */
600close(imsg_fds[1]);
601imsg_init(&parent_ibuf, imsg_fds[0]);
602exit(parent_main(&parent_ibuf));
603.Ed
604.Pp
605Messages may then be composed and queued on the
606.Em imsgbuf ,
607for example using the
608.Fn imsg_compose
609function:
610.Bd -literal -offset indent
611enum imsg_type {
612	IMSG_A_MESSAGE,
613	IMSG_MESSAGE2
614};
615
616int
617child_main(struct imsgbuf *ibuf)
618{
619	int	idata;
620	...
621	idata = 42;
622	imsg_compose(ibuf, IMSG_A_MESSAGE,
623	    0, 0, -1, &idata, sizeof idata);
624	...
625}
626.Ed
627.Pp
628A mechanism such as
629.Xr poll 2
630or the
631.Xr event 3
632library is used to monitor the socket file descriptor.
633When the socket is ready for writing, queued messages are transmitted with
634.Fn msgbuf_write :
635.Bd -literal -offset indent
636	if ((n = msgbuf_write(&ibuf-\*(Gtw)) == -1 && errno != EAGAIN) {
637		/* handle write failure */
638	}
639	if (n == 0) {
640		/* handle closed connection */
641	}
642.Ed
643.Pp
644And when ready for reading, messages are first received using
645.Fn imsg_read
646and then extracted with
647.Fn imsg_get :
648.Bd -literal -offset indent
649void
650dispatch_imsg(struct imsgbuf *ibuf)
651{
652	struct imsg	imsg;
653	ssize_t         n, datalen;
654	int		idata;
655
656	if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) {
657		/* handle read error */
658	}
659	if (n == 0) {
660		/* handle closed connection */
661	}
662
663	for (;;) {
664		if ((n = imsg_get(ibuf, &imsg)) == -1) {
665			/* handle read error */
666		}
667		if (n == 0)	/* no more messages */
668			return;
669		datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
670
671		switch (imsg.hdr.type) {
672		case IMSG_A_MESSAGE:
673			if (datalen \*(Lt sizeof idata) {
674				/* handle corrupt message */
675			}
676			memcpy(&idata, imsg.data, sizeof idata);
677			/* handle message received */
678			break;
679		...
680		}
681
682		imsg_free(&imsg);
683	}
684}
685.Ed
686.Sh SEE ALSO
687.Xr socketpair 2 ,
688.Xr unix 4
689