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