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