1.\" $OpenBSD: imsg_init.3,v 1.24 2020/12/15 13:40:22 jmc 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: December 15 2020 $ 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, \-1 otherwise. 191.Pp 192.Fn imsg_close 193completes creation of 194.Fa msg 195by adding it to 196.Fa ibuf 197output buffer. 198.Pp 199.Fn imsg_compose 200is a routine which is used to quickly create and queue an imsg. 201It takes the same parameters as the 202.Fn imsg_create , 203.Fn imsg_add 204and 205.Fn imsg_close 206routines, 207except that only one ancillary data buffer can be provided. 208Additionally, the file descriptor 209.Fa fd 210may be passed over the socket to the other process. 211If 212.Fa fd 213is given, it is closed in the sending program after the message is sent. 214A value of \-1 indicates no file descriptor should be passed. 215This routine returns 1 if it succeeds, \-1 otherwise. 216.Pp 217.Fn imsg_composev 218is similar to 219.Fn imsg_compose . 220It takes the same parameters, except that the ancillary data buffer is specified 221by 222.Fa iovec . 223.Pp 224.Fn imsg_flush 225is a function which calls 226.Fn msgbuf_write 227in a loop until all imsgs in the output buffer are sent. 228It returns 0 if it succeeds, \-1 otherwise. 229.Pp 230The 231.Fn imsg_read 232routine reads pending data with 233.Xr recvmsg 2 234and queues it as individual messages on 235.Fa imsgbuf . 236It returns the number of bytes read on success, or \-1 on error. 237A return value of \-1 from 238.Fn imsg_read 239invalidates 240.Fa imsgbuf , 241and renders it suitable only for passing to 242.Fn imsg_clear . 243.Pp 244.Fn imsg_get 245fills in an individual imsg pending on 246.Fa imsgbuf 247into the structure pointed to by 248.Fa imsg . 249It returns the total size of the message, 0 if no messages are ready, or \-1 250for an error. 251Received messages are returned as a 252.Em struct imsg , 253which must be freed by 254.Fn imsg_free 255when no longer required. 256.Em struct imsg 257has this form: 258.Bd -literal -offset indent 259struct imsg { 260 struct imsg_hdr hdr; 261 int fd; 262 void *data; 263}; 264 265struct imsg_hdr { 266 uint32_t type; 267 uint16_t len; 268 uint16_t flags; 269 uint32_t peerid; 270 uint32_t pid; 271}; 272.Ed 273.Pp 274The header members are: 275.Bl -tag -width Ds -offset indent 276.It type 277A integer identifier, typically used to express the meaning of the message. 278.It len 279The total length of the imsg, including the header and any ancillary data 280transmitted with the message (pointed to by the 281.Em data 282member of the message itself). 283.It flags 284Flags used internally by the imsg functions: should not be used by application 285programs. 286.It peerid, pid 28732-bit values specified on message creation and free for any use by the 288caller, normally used to identify the message sender. 289.El 290.Pp 291In addition, 292.Em struct imsg 293has the following: 294.Bl -tag -width Ds -offset indent 295.It fd 296The file descriptor specified when the message was created and passed using the 297socket control message API, or \-1 if no file descriptor was sent. 298.It data 299A pointer to the ancillary data transmitted with the imsg. 300.El 301.Pp 302The IMSG_HEADER_SIZE define is the size of the imsg message header, which 303may be subtracted from the 304.Fa len 305member of 306.Em struct imsg_hdr 307to obtain the length of any additional data passed with the message. 308.Pp 309MAX_IMSGSIZE is defined as the maximum size of a single imsg, currently 31016384 bytes. 311.Sh BUFFERS 312The imsg API defines functions to manipulate buffers, used internally and during 313construction of imsgs with 314.Fn imsg_create . 315A 316.Em struct ibuf 317is a single buffer and a 318.Em struct msgbuf 319a queue of output buffers for transmission: 320.Bd -literal -offset indent 321struct ibuf { 322 TAILQ_ENTRY(ibuf) entry; 323 unsigned char *buf; 324 size_t size; 325 size_t max; 326 size_t wpos; 327 size_t rpos; 328 int fd; 329}; 330 331struct msgbuf { 332 TAILQ_HEAD(, ibuf) bufs; 333 uint32_t queued; 334 int fd; 335}; 336.Ed 337.Pp 338The 339.Fn ibuf_open 340function allocates a fixed-length buffer. 341The buffer may not be resized and may contain a maximum of 342.Fa len 343bytes. 344On success 345.Fn ibuf_open 346returns a pointer to the buffer; on failure it returns NULL. 347.Pp 348.Fn ibuf_dynamic 349allocates a resizeable buffer of initial length 350.Fa len 351and maximum size 352.Fa max . 353Buffers allocated with 354.Fn ibuf_dynamic 355are automatically grown if necessary when data is added. 356.Pp 357.Fn ibuf_add 358is a routine which appends a block of data to 359.Fa buf . 3600 is returned on success and \-1 on failure. 361.Pp 362.Fn ibuf_reserve 363is used to reserve 364.Fa len 365bytes in 366.Fa buf . 367A pointer to the start of the reserved space is returned, or NULL on error. 368.Pp 369.Fn ibuf_seek 370is a function which returns a pointer to the part of the buffer at offset 371.Fa pos 372and of extent 373.Fa len . 374NULL is returned if the requested range is outside the part of the buffer 375in use. 376.Pp 377.Fn ibuf_size 378and 379.Fn ibuf_left 380are functions which return the total bytes used and available in 381.Fa buf 382respectively. 383.Pp 384.Fn ibuf_close 385appends 386.Fa buf 387to 388.Fa msgbuf 389ready to be sent. 390.Pp 391The 392.Fn ibuf_write 393routine transmits as many pending buffers as possible from 394.Fa msgbuf 395using 396.Xr writev 2 . 397It returns 1 if it succeeds, \-1 on error and 0 when no buffers were 398pending or an EOF condition on the socket is detected. 399Temporary resource shortages are returned with errno 400.Er EAGAIN 401and require the application to retry again in the future. 402.Pp 403.Fn ibuf_free 404frees 405.Fa buf 406and any associated storage. 407If 408.Fa buf 409is a NULL pointer, no action occurs. 410.Pp 411The 412.Fn msgbuf_init 413function initializes 414.Fa msgbuf 415so that buffers may be appended to it. 416The 417.Em fd 418member should also be set directly before 419.Fn msgbuf_write 420is used. 421.Pp 422.Fn msgbuf_clear 423empties a msgbuf, removing and discarding any queued buffers. 424.Pp 425The 426.Fn msgbuf_write 427routine calls 428.Xr sendmsg 2 429to transmit buffers queued in 430.Fa msgbuf . 431It returns 1 if it succeeds, \-1 on error, and 0 when the queue was empty 432or an EOF condition on the socket is detected. 433Temporary resource shortages are returned with errno 434.Er EAGAIN 435and require the application to retry again in the future. 436.Pp 437.Fn msgbuf_drain 438discards data from buffers queued in 439.Fa msgbuf 440until 441.Fa n 442bytes have been removed or 443.Fa msgbuf 444is empty. 445.Sh EXAMPLES 446In a typical program, a channel between two processes is created with 447.Xr socketpair 2 , 448and an 449.Em imsgbuf 450created around one file descriptor in each process: 451.Bd -literal -offset indent 452struct imsgbuf parent_ibuf, child_ibuf; 453int imsg_fds[2]; 454 455if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_fds) == -1) 456 err(1, "socketpair"); 457 458switch (fork()) { 459case -1: 460 err(1, "fork"); 461case 0: 462 /* child */ 463 close(imsg_fds[0]); 464 imsg_init(&child_ibuf, imsg_fds[1]); 465 exit(child_main(&child_ibuf)); 466} 467 468/* parent */ 469close(imsg_fds[1]); 470imsg_init(&parent_ibuf, imsg_fds[0]); 471exit(parent_main(&parent_ibuf)); 472.Ed 473.Pp 474Messages may then be composed and queued on the 475.Em imsgbuf , 476for example using the 477.Fn imsg_compose 478function: 479.Bd -literal -offset indent 480enum imsg_type { 481 IMSG_A_MESSAGE, 482 IMSG_MESSAGE2 483}; 484 485int 486child_main(struct imsgbuf *ibuf) 487{ 488 int idata; 489 ... 490 idata = 42; 491 imsg_compose(ibuf, IMSG_A_MESSAGE, 492 0, 0, -1, &idata, sizeof idata); 493 ... 494} 495.Ed 496.Pp 497A mechanism such as 498.Xr poll 2 499or the 500.Xr event 3 501library is used to monitor the socket file descriptor. 502When the socket is ready for writing, queued messages are transmitted with 503.Fn msgbuf_write : 504.Bd -literal -offset indent 505 if ((n = msgbuf_write(&ibuf-\*(Gtw)) == -1 && errno != EAGAIN) { 506 /* handle write failure */ 507 } 508 if (n == 0) { 509 /* handle closed connection */ 510 } 511.Ed 512.Pp 513And when ready for reading, messages are first received using 514.Fn imsg_read 515and then extracted with 516.Fn imsg_get : 517.Bd -literal -offset indent 518void 519dispatch_imsg(struct imsgbuf *ibuf) 520{ 521 struct imsg imsg; 522 ssize_t n, datalen; 523 int idata; 524 525 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) { 526 /* handle read error */ 527 } 528 if (n == 0) { 529 /* handle closed connection */ 530 } 531 532 for (;;) { 533 if ((n = imsg_get(ibuf, &imsg)) == -1) { 534 /* handle read error */ 535 } 536 if (n == 0) /* no more messages */ 537 return; 538 datalen = imsg.hdr.len - IMSG_HEADER_SIZE; 539 540 switch (imsg.hdr.type) { 541 case IMSG_A_MESSAGE: 542 if (datalen \*(Lt sizeof idata) { 543 /* handle corrupt message */ 544 } 545 memcpy(&idata, imsg.data, sizeof idata); 546 /* handle message received */ 547 break; 548 ... 549 } 550 551 imsg_free(&imsg); 552 } 553} 554.Ed 555.Sh SEE ALSO 556.Xr socketpair 2 , 557.Xr unix 4 558