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