1.\" $OpenBSD: imsg_init.3,v 1.25 2022/05/19 08:05:23 stsp 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: May 19 2022 $ 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_create , 27.Nm imsg_add , 28.Nm imsg_close , 29.Nm imsg_free , 30.Nm imsg_flush , 31.Nm imsg_clear , 32.Nm ibuf_open , 33.Nm ibuf_dynamic , 34.Nm ibuf_add , 35.Nm ibuf_reserve , 36.Nm ibuf_seek , 37.Nm ibuf_size , 38.Nm ibuf_left , 39.Nm ibuf_close , 40.Nm ibuf_write , 41.Nm ibuf_free , 42.Nm msgbuf_init , 43.Nm msgbuf_clear , 44.Nm msgbuf_write , 45.Nm msgbuf_drain 46.Nd IPC messaging functions 47.Sh SYNOPSIS 48.In sys/types.h 49.In sys/queue.h 50.In sys/uio.h 51.In stdint.h 52.In imsg.h 53.Ft void 54.Fn imsg_init "struct imsgbuf *ibuf" "int fd" 55.Ft ssize_t 56.Fn imsg_read "struct imsgbuf *ibuf" 57.Ft ssize_t 58.Fn imsg_get "struct imsgbuf *ibuf" "struct imsg *imsg" 59.Ft int 60.Fn imsg_compose "struct imsgbuf *ibuf" "uint32_t type" "uint32_t peerid" \ 61 "pid_t pid" "int fd" "const void *data" "uint16_t datalen" 62.Ft int 63.Fn imsg_composev "struct imsgbuf *ibuf" "uint32_t type" "uint32_t peerid" \ 64 "pid_t pid" "int fd" "const struct iovec *iov" "int iovcnt" 65.Ft "struct ibuf *" 66.Fn imsg_create "struct imsgbuf *ibuf" "uint32_t type" "uint32_t peerid" \ 67 "pid_t pid" "uint16_t datalen" 68.Ft int 69.Fn imsg_add "struct ibuf *msg" "const void *data" "uint16_t datalen" 70.Ft void 71.Fn imsg_close "struct imsgbuf *ibuf" "struct ibuf *msg" 72.Ft void 73.Fn imsg_free "struct imsg *imsg" 74.Ft int 75.Fn imsg_flush "struct imsgbuf *ibuf" 76.Ft void 77.Fn imsg_clear "struct imsgbuf *ibuf" 78.Ft "struct ibuf *" 79.Fn ibuf_open "size_t len" 80.Ft "struct ibuf *" 81.Fn ibuf_dynamic "size_t len" "size_t max" 82.Ft int 83.Fn ibuf_add "struct ibuf *buf" "const void *data" "size_t len" 84.Ft "void *" 85.Fn ibuf_reserve "struct ibuf *buf" "size_t len" 86.Ft "void *" 87.Fn ibuf_seek "struct ibuf *buf" "size_t pos" "size_t len" 88.Ft size_t 89.Fn ibuf_size "struct ibuf *buf" 90.Ft size_t 91.Fn ibuf_left "struct ibuf *buf" 92.Ft void 93.Fn ibuf_close "struct msgbuf *msgbuf" "struct ibuf *buf" 94.Ft int 95.Fn ibuf_write "struct msgbuf *msgbuf" 96.Ft void 97.Fn ibuf_free "struct ibuf *buf" 98.Ft void 99.Fn msgbuf_init "struct msgbuf *msgbuf" 100.Ft void 101.Fn msgbuf_clear "struct msgbuf *msgbuf" 102.Ft int 103.Fn msgbuf_write "struct msgbuf *msgbuf" 104.Ft void 105.Fn msgbuf_drain "struct msgbuf *msgbuf" "size_t n" 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 119The basic 120.Nm 121structure is the 122.Em imsgbuf , 123which wraps a file descriptor and represents one side of a channel on which 124messages are sent and received: 125.Bd -literal -offset indent 126struct imsgbuf { 127 TAILQ_HEAD(, imsg_fd) fds; 128 struct ibuf_read r; 129 struct msgbuf w; 130 int fd; 131 pid_t pid; 132}; 133.Ed 134.Pp 135.Fn imsg_init 136is a routine which initializes 137.Fa ibuf 138as one side of a channel associated with 139.Fa fd . 140The file descriptor is used to send and receive messages, 141but is not closed by any of the imsg functions. 142An imsgbuf is initialized with the 143.Em w 144member as the output buffer queue, 145.Em fd 146with the file descriptor passed to 147.Fn imsg_init 148and the other members for internal use only. 149.Pp 150The 151.Fn imsg_clear 152function frees any data allocated as part of an imsgbuf. 153.Pp 154.Fn imsg_create , 155.Fn imsg_add 156and 157.Fn imsg_close 158are generic construction routines for messages that are to be sent using an 159imsgbuf. 160.Pp 161.Fn imsg_create 162creates a new message with header specified by 163.Fa type , 164.Fa peerid 165and 166.Fa pid . 167A 168.Fa pid 169of zero uses the process ID returned by 170.Xr getpid 2 171when 172.Fa ibuf 173was initialized. 174In addition to this common imsg header, 175.Fa datalen 176bytes of space may be reserved for attaching to this imsg. 177This space is populated using 178.Fn imsg_add . 179.Fn imsg_create 180returns a pointer to a new message if it succeeds, NULL otherwise. 181.Pp 182.Fn imsg_add 183appends to 184.Fa msg 185.Fa datalen 186bytes of ancillary data pointed to by 187.Fa data . 188It returns 189.Fa datalen 190if it succeeds, otherwise 191.Fa msg 192is freed and \-1 is returned. 193.Pp 194.Fn imsg_close 195completes creation of 196.Fa msg 197by adding it to 198.Fa ibuf 199output buffer. 200.Pp 201.Fn imsg_compose 202is a routine which is used to quickly create and queue an imsg. 203It takes the same parameters as the 204.Fn imsg_create , 205.Fn imsg_add 206and 207.Fn imsg_close 208routines, 209except that only one ancillary data buffer can be provided. 210Additionally, the file descriptor 211.Fa fd 212may be passed over the socket to the other process. 213If 214.Fa fd 215is given, it is closed in the sending program after the message is sent. 216A value of \-1 indicates no file descriptor should be passed. 217This routine returns 1 if it succeeds, \-1 otherwise. 218.Pp 219.Fn imsg_composev 220is similar to 221.Fn imsg_compose . 222It takes the same parameters, except that the ancillary data buffer is specified 223by 224.Fa iovec . 225.Pp 226.Fn imsg_flush 227is a function which calls 228.Fn msgbuf_write 229in a loop until all imsgs in the output buffer are sent. 230It returns 0 if it succeeds, \-1 otherwise. 231.Pp 232The 233.Fn imsg_read 234routine reads pending data with 235.Xr recvmsg 2 236and queues it as individual messages on 237.Fa imsgbuf . 238It returns the number of bytes read on success, or \-1 on error. 239A return value of \-1 from 240.Fn imsg_read 241invalidates 242.Fa imsgbuf , 243and renders it suitable only for passing to 244.Fn imsg_clear . 245.Pp 246.Fn imsg_get 247fills in an individual imsg pending on 248.Fa imsgbuf 249into the structure pointed to by 250.Fa imsg . 251It returns the total size of the message, 0 if no messages are ready, or \-1 252for an error. 253Received messages are returned as a 254.Em struct imsg , 255which must be freed by 256.Fn imsg_free 257when no longer required. 258.Em struct imsg 259has this form: 260.Bd -literal -offset indent 261struct imsg { 262 struct imsg_hdr hdr; 263 int fd; 264 void *data; 265}; 266 267struct imsg_hdr { 268 uint32_t type; 269 uint16_t len; 270 uint16_t flags; 271 uint32_t peerid; 272 uint32_t pid; 273}; 274.Ed 275.Pp 276The header members are: 277.Bl -tag -width Ds -offset indent 278.It type 279A integer identifier, typically used to express the meaning of the message. 280.It len 281The total length of the imsg, including the header and any ancillary data 282transmitted with the message (pointed to by the 283.Em data 284member of the message itself). 285.It flags 286Flags used internally by the imsg functions: should not be used by application 287programs. 288.It peerid, pid 28932-bit values specified on message creation and free for any use by the 290caller, normally used to identify the message sender. 291.El 292.Pp 293In addition, 294.Em struct imsg 295has the following: 296.Bl -tag -width Ds -offset indent 297.It fd 298The file descriptor specified when the message was created and passed using the 299socket control message API, or \-1 if no file descriptor was sent. 300.It data 301A pointer to the ancillary data transmitted with the imsg. 302.El 303.Pp 304The IMSG_HEADER_SIZE define is the size of the imsg message header, which 305may be subtracted from the 306.Fa len 307member of 308.Em struct imsg_hdr 309to obtain the length of any additional data passed with the message. 310.Pp 311MAX_IMSGSIZE is defined as the maximum size of a single imsg, currently 31216384 bytes. 313.Sh BUFFERS 314The imsg API defines functions to manipulate buffers, used internally and during 315construction of imsgs with 316.Fn imsg_create . 317A 318.Em struct ibuf 319is a single buffer and a 320.Em struct msgbuf 321a queue of output buffers for transmission: 322.Bd -literal -offset indent 323struct ibuf { 324 TAILQ_ENTRY(ibuf) entry; 325 unsigned char *buf; 326 size_t size; 327 size_t max; 328 size_t wpos; 329 size_t rpos; 330 int fd; 331}; 332 333struct msgbuf { 334 TAILQ_HEAD(, ibuf) bufs; 335 uint32_t queued; 336 int fd; 337}; 338.Ed 339.Pp 340The 341.Fn ibuf_open 342function allocates a fixed-length buffer. 343The buffer may not be resized and may contain a maximum of 344.Fa len 345bytes. 346On success 347.Fn ibuf_open 348returns a pointer to the buffer; on failure it returns NULL. 349.Pp 350.Fn ibuf_dynamic 351allocates a resizeable buffer of initial length 352.Fa len 353and maximum size 354.Fa max . 355Buffers allocated with 356.Fn ibuf_dynamic 357are automatically grown if necessary when data is added. 358.Pp 359.Fn ibuf_add 360is a routine which appends a block of data to 361.Fa buf . 3620 is returned on success and \-1 on failure. 363.Pp 364.Fn ibuf_reserve 365is used to reserve 366.Fa len 367bytes in 368.Fa buf . 369A pointer to the start of the reserved space is returned, or NULL on error. 370.Pp 371.Fn ibuf_seek 372is a function which returns a pointer to the part of the buffer at offset 373.Fa pos 374and of extent 375.Fa len . 376NULL is returned if the requested range is outside the part of the buffer 377in use. 378.Pp 379.Fn ibuf_size 380and 381.Fn ibuf_left 382are functions which return the total bytes used and available in 383.Fa buf 384respectively. 385.Pp 386.Fn ibuf_close 387appends 388.Fa buf 389to 390.Fa msgbuf 391ready to be sent. 392.Pp 393The 394.Fn ibuf_write 395routine transmits as many pending buffers as possible from 396.Fa msgbuf 397using 398.Xr writev 2 . 399It returns 1 if it succeeds, \-1 on error and 0 when no buffers were 400pending or an EOF condition on the socket is detected. 401Temporary resource shortages are returned with errno 402.Er EAGAIN 403and require the application to retry again in the future. 404.Pp 405.Fn ibuf_free 406frees 407.Fa buf 408and any associated storage. 409If 410.Fa buf 411is a NULL pointer, no action occurs. 412.Pp 413The 414.Fn msgbuf_init 415function initializes 416.Fa msgbuf 417so that buffers may be appended to it. 418The 419.Em fd 420member should also be set directly before 421.Fn msgbuf_write 422is used. 423.Pp 424.Fn msgbuf_clear 425empties a msgbuf, removing and discarding any queued buffers. 426.Pp 427The 428.Fn msgbuf_write 429routine calls 430.Xr sendmsg 2 431to transmit buffers queued in 432.Fa msgbuf . 433It returns 1 if it succeeds, \-1 on error, and 0 when the queue was empty 434or an EOF condition on the socket is detected. 435Temporary resource shortages are returned with errno 436.Er EAGAIN 437and require the application to retry again in the future. 438.Pp 439.Fn msgbuf_drain 440discards data from buffers queued in 441.Fa msgbuf 442until 443.Fa n 444bytes have been removed or 445.Fa msgbuf 446is empty. 447.Sh EXAMPLES 448In a typical program, a channel between two processes is created with 449.Xr socketpair 2 , 450and an 451.Em imsgbuf 452created around one file descriptor in each process: 453.Bd -literal -offset indent 454struct imsgbuf parent_ibuf, child_ibuf; 455int imsg_fds[2]; 456 457if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_fds) == -1) 458 err(1, "socketpair"); 459 460switch (fork()) { 461case -1: 462 err(1, "fork"); 463case 0: 464 /* child */ 465 close(imsg_fds[0]); 466 imsg_init(&child_ibuf, imsg_fds[1]); 467 exit(child_main(&child_ibuf)); 468} 469 470/* parent */ 471close(imsg_fds[1]); 472imsg_init(&parent_ibuf, imsg_fds[0]); 473exit(parent_main(&parent_ibuf)); 474.Ed 475.Pp 476Messages may then be composed and queued on the 477.Em imsgbuf , 478for example using the 479.Fn imsg_compose 480function: 481.Bd -literal -offset indent 482enum imsg_type { 483 IMSG_A_MESSAGE, 484 IMSG_MESSAGE2 485}; 486 487int 488child_main(struct imsgbuf *ibuf) 489{ 490 int idata; 491 ... 492 idata = 42; 493 imsg_compose(ibuf, IMSG_A_MESSAGE, 494 0, 0, -1, &idata, sizeof idata); 495 ... 496} 497.Ed 498.Pp 499A mechanism such as 500.Xr poll 2 501or the 502.Xr event 3 503library is used to monitor the socket file descriptor. 504When the socket is ready for writing, queued messages are transmitted with 505.Fn msgbuf_write : 506.Bd -literal -offset indent 507 if ((n = msgbuf_write(&ibuf-\*(Gtw)) == -1 && errno != EAGAIN) { 508 /* handle write failure */ 509 } 510 if (n == 0) { 511 /* handle closed connection */ 512 } 513.Ed 514.Pp 515And when ready for reading, messages are first received using 516.Fn imsg_read 517and then extracted with 518.Fn imsg_get : 519.Bd -literal -offset indent 520void 521dispatch_imsg(struct imsgbuf *ibuf) 522{ 523 struct imsg imsg; 524 ssize_t n, datalen; 525 int idata; 526 527 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) { 528 /* handle read error */ 529 } 530 if (n == 0) { 531 /* handle closed connection */ 532 } 533 534 for (;;) { 535 if ((n = imsg_get(ibuf, &imsg)) == -1) { 536 /* handle read error */ 537 } 538 if (n == 0) /* no more messages */ 539 return; 540 datalen = imsg.hdr.len - IMSG_HEADER_SIZE; 541 542 switch (imsg.hdr.type) { 543 case IMSG_A_MESSAGE: 544 if (datalen \*(Lt sizeof idata) { 545 /* handle corrupt message */ 546 } 547 memcpy(&idata, imsg.data, sizeof idata); 548 /* handle message received */ 549 break; 550 ... 551 } 552 553 imsg_free(&imsg); 554 } 555} 556.Ed 557.Sh SEE ALSO 558.Xr socketpair 2 , 559.Xr unix 4 560