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