1 /* $NetBSD: vstream.c,v 1.4 2022/10/08 16:12:50 christos Exp $ */ 2 3 /*++ 4 /* NAME 5 /* vstream 3 6 /* SUMMARY 7 /* light-weight buffered I/O package 8 /* SYNOPSIS 9 /* #include <vstream.h> 10 /* 11 /* VSTREAM *vstream_fopen(path, flags, mode) 12 /* const char *path; 13 /* int flags; 14 /* mode_t mode; 15 /* 16 /* VSTREAM *vstream_fdopen(fd, flags) 17 /* int fd; 18 /* int flags; 19 /* 20 /* VSTREAM *vstream_memopen(string, flags) 21 /* VSTRING *string; 22 /* int flags; 23 /* 24 /* VSTREAM *vstream_memreopen(stream, string, flags) 25 /* VSTREAM *stream; 26 /* VSTRING *string; 27 /* int flags; 28 /* 29 /* int vstream_fclose(stream) 30 /* VSTREAM *stream; 31 /* 32 /* int vstream_fdclose(stream) 33 /* VSTREAM *stream; 34 /* 35 /* VSTREAM *vstream_printf(format, ...) 36 /* const char *format; 37 /* 38 /* VSTREAM *vstream_fprintf(stream, format, ...) 39 /* VSTREAM *stream; 40 /* const char *format; 41 /* 42 /* int VSTREAM_GETC(stream) 43 /* VSTREAM *stream; 44 /* 45 /* int VSTREAM_PUTC(ch, stream) 46 /* int ch; 47 /* 48 /* int VSTREAM_GETCHAR(void) 49 /* 50 /* int VSTREAM_PUTCHAR(ch) 51 /* int ch; 52 /* 53 /* int vstream_ungetc(stream, ch) 54 /* VSTREAM *stream; 55 /* int ch; 56 /* 57 /* int vstream_fputs(str, stream) 58 /* const char *str; 59 /* VSTREAM *stream; 60 /* 61 /* off_t vstream_ftell(stream) 62 /* VSTREAM *stream; 63 /* 64 /* off_t vstream_fseek(stream, offset, whence) 65 /* VSTREAM *stream; 66 /* off_t offset; 67 /* int whence; 68 /* 69 /* int vstream_fflush(stream) 70 /* VSTREAM *stream; 71 /* 72 /* int vstream_fpurge(stream, direction) 73 /* VSTREAM *stream; 74 /* int direction; 75 /* 76 /* ssize_t vstream_fread(stream, buf, len) 77 /* VSTREAM *stream; 78 /* void *buf; 79 /* ssize_t len; 80 /* 81 /* ssize_t vstream_fwrite(stream, buf, len) 82 /* VSTREAM *stream; 83 /* void *buf; 84 /* ssize_t len; 85 /* 86 /* ssize_t vstream_fread_app(stream, buf, len) 87 /* VSTREAM *stream; 88 /* VSTRING *buf; 89 /* ssize_t len; 90 /* 91 /* ssize_t vstream_fread_buf(stream, buf, len) 92 /* VSTREAM *stream; 93 /* VSTRING *buf; 94 /* ssize_t len; 95 /* 96 /* void vstream_control(stream, name, ...) 97 /* VSTREAM *stream; 98 /* int name; 99 /* 100 /* int vstream_fileno(stream) 101 /* VSTREAM *stream; 102 /* 103 /* const ssize_t vstream_req_bufsize(stream) 104 /* VSTREAM *stream; 105 /* 106 /* void *vstream_context(stream) 107 /* VSTREAM *stream; 108 /* 109 /* int vstream_ferror(stream) 110 /* VSTREAM *stream; 111 /* 112 /* int vstream_ftimeout(stream) 113 /* VSTREAM *stream; 114 /* 115 /* int vstream_feof(stream) 116 /* VSTREAM *stream; 117 /* 118 /* int vstream_clearerr(stream) 119 /* VSTREAM *stream; 120 /* 121 /* const char *VSTREAM_PATH(stream) 122 /* VSTREAM *stream; 123 /* 124 /* char *vstream_vprintf(format, ap) 125 /* const char *format; 126 /* va_list *ap; 127 /* 128 /* char *vstream_vfprintf(stream, format, ap) 129 /* VSTREAM *stream; 130 /* const char *format; 131 /* va_list *ap; 132 /* 133 /* ssize_t vstream_bufstat(stream, command) 134 /* VSTREAM *stream; 135 /* int command; 136 /* 137 /* ssize_t vstream_peek(stream) 138 /* VSTREAM *stream; 139 /* 140 /* const char *vstream_peek_data(stream) 141 /* VSTREAM *stream; 142 /* 143 /* int vstream_setjmp(stream) 144 /* VSTREAM *stream; 145 /* 146 /* void vstream_longjmp(stream, val) 147 /* VSTREAM *stream; 148 /* int val; 149 /* 150 /* time_t vstream_ftime(stream) 151 /* VSTREAM *stream; 152 /* 153 /* struct timeval vstream_ftimeval(stream) 154 /* VSTREAM *stream; 155 /* 156 /* int vstream_rd_error(stream) 157 /* VSTREAM *stream; 158 /* 159 /* int vstream_wr_error(stream) 160 /* VSTREAM *stream; 161 /* 162 /* int vstream_rd_timeout(stream) 163 /* VSTREAM *stream; 164 /* 165 /* int vstream_wr_timeout(stream) 166 /* VSTREAM *stream; 167 /* 168 /* int vstream_fstat(stream, flags) 169 /* VSTREAM *stream; 170 /* int flags; 171 /* DESCRIPTION 172 /* The \fIvstream\fR module implements light-weight buffered I/O 173 /* similar to the standard I/O routines. 174 /* 175 /* The interface is implemented in terms of VSTREAM structure 176 /* pointers, also called streams. For convenience, three streams 177 /* are predefined: VSTREAM_IN, VSTREAM_OUT, and VSTREAM_ERR. These 178 /* streams are connected to the standard input, output and error 179 /* file descriptors, respectively. 180 /* 181 /* Although the interface is patterned after the standard I/O 182 /* library, there are some major differences: 183 /* .IP \(bu 184 /* File descriptors are not limited to the range 0..255. This 185 /* was reason #1 to write these routines in the first place. 186 /* .IP \(bu 187 /* The application can switch between reading and writing on 188 /* the same stream without having to perform a flush or seek 189 /* operation, and can change write position without having to 190 /* flush. This was reason #2. Upon position or direction change, 191 /* unread input is discarded, and unwritten output is flushed 192 /* automatically. Exception: with double-buffered streams, unread 193 /* input is not discarded upon change of I/O direction, and 194 /* output flushing is delayed until the read buffer must be refilled. 195 /* .IP \(bu 196 /* A bidirectional stream can read and write with the same buffer 197 /* and file descriptor, or it can have separate read/write 198 /* buffers and/or file descriptors. 199 /* .IP \(bu 200 /* No automatic flushing of VSTREAM_OUT upon program exit, or of 201 /* VSTREAM_ERR at any time. No unbuffered or line buffered modes. 202 /* This functionality may be added when it is really needed. 203 /* .PP 204 /* vstream_fopen() opens the named file and associates a buffered 205 /* stream with it. The \fIpath\fR, \fIflags\fR and \fImode\fR 206 /* arguments are passed on to the open(2) routine. The result is 207 /* a null pointer in case of problems. The \fIpath\fR argument is 208 /* copied and can be looked up with VSTREAM_PATH(). 209 /* 210 /* vstream_fdopen() takes an open file and associates a buffered 211 /* stream with it. The \fIflags\fR argument specifies how the file 212 /* was opened. vstream_fdopen() either succeeds or never returns. 213 /* 214 /* vstream_memopen() opens a VSTRING as a stream. The \fIflags\fR 215 /* argument must specify one of O_RDONLY, O_WRONLY, or O_APPEND. 216 /* vstream_memopen() either succeeds or never returns. Streams 217 /* opened with vstream_memopen() have limitations: they can't 218 /* be opened in read/write mode, they can't seek beyond the 219 /* end of the VSTRING, and they don't support vstream_control() 220 /* methods that manipulate buffers, file descriptors, or I/O 221 /* functions. After a VSTRING is opened for writing, its content 222 /* will be in an indeterminate state while the stream is open, 223 /* and will be null-terminated when the stream is closed. 224 /* 225 /* vstream_memreopen() reopens a memory stream. When the 226 /* \fIstream\fR argument is a null pointer, the behavior is that 227 /* of vstream_memopen(). 228 /* 229 /* vstream_fclose() closes the named buffered stream. The result 230 /* is 0 in case of success, VSTREAM_EOF in case of problems. 231 /* vstream_fclose() reports the same errors as vstream_ferror(). 232 /* 233 /* vstream_fdclose() leaves the file(s) open but is otherwise 234 /* identical to vstream_fclose(). 235 /* 236 /* vstream_fprintf() formats its arguments according to the 237 /* \fIformat\fR argument and writes the result to the named stream. 238 /* The result is the stream argument. It understands the s, c, d, u, 239 /* o, x, X, e, f and g format types, the l modifier, field width and 240 /* precision, sign, and padding with zeros or spaces. In addition, 241 /* vstream_fprintf() recognizes the %m format specifier and expands 242 /* it to the error message corresponding to the current value of the 243 /* global \fIerrno\fR variable. 244 /* 245 /* vstream_printf() performs formatted output to the standard output 246 /* stream. 247 /* 248 /* VSTREAM_GETC() reads the next character from the named stream. 249 /* The result is VSTREAM_EOF when end-of-file is reached or if a read 250 /* error was detected. VSTREAM_GETC() is an unsafe macro that 251 /* evaluates some arguments more than once. 252 /* 253 /* VSTREAM_GETCHAR() is an alias for VSTREAM_GETC(VSTREAM_IN). 254 /* 255 /* VSTREAM_PUTC() appends the specified character to the specified 256 /* stream. The result is the stored character, or VSTREAM_EOF in 257 /* case of problems. VSTREAM_PUTC() is an unsafe macro that 258 /* evaluates some arguments more than once. 259 /* 260 /* VSTREAM_PUTCHAR(c) is an alias for VSTREAM_PUTC(c, VSTREAM_OUT). 261 /* 262 /* vstream_ungetc() pushes back a character onto the specified stream 263 /* and returns the character, or VSTREAM_EOF in case of problems. 264 /* It is an error to push back before reading (or immediately after 265 /* changing the stream offset via vstream_fseek()). Upon successful 266 /* return, vstream_ungetc() clears the end-of-file stream flag. 267 /* 268 /* vstream_fputs() appends the given null-terminated string to the 269 /* specified buffered stream. The result is 0 in case of success, 270 /* VSTREAM_EOF in case of problems. 271 /* 272 /* vstream_ftell() returns the file offset for the specified stream, 273 /* -1 if the stream is connected to a non-seekable file. 274 /* 275 /* vstream_fseek() changes the file position for the next read or write 276 /* operation. Unwritten output is flushed. With unidirectional streams, 277 /* unread input is discarded. The \fIoffset\fR argument specifies the file 278 /* position from the beginning of the file (\fIwhence\fR is SEEK_SET), 279 /* from the current file position (\fIwhence\fR is SEEK_CUR), or from 280 /* the file end (SEEK_END). The result value is the file offset 281 /* from the beginning of the file, -1 in case of problems. 282 /* 283 /* vstream_fflush() flushes unwritten data to a file that was 284 /* opened in read-write or write-only mode. 285 /* vstream_fflush() returns 0 in case of success, VSTREAM_EOF in 286 /* case of problems. It is an error to flush a read-only stream. 287 /* vstream_fflush() reports the same errors as vstream_ferror(). 288 /* 289 /* vstream_fpurge() discards the contents of the stream buffer. 290 /* If direction is VSTREAM_PURGE_READ, it discards unread data, 291 /* else if direction is VSTREAM_PURGE_WRITE, it discards unwritten 292 /* data. In the case of a double-buffered stream, if direction is 293 /* VSTREAM_PURGE_BOTH, it discards the content of both the read 294 /* and write buffers. vstream_fpurge() returns 0 in case of success, 295 /* VSTREAM_EOF in case of problems. 296 /* 297 /* vstream_fread() and vstream_fwrite() perform unformatted I/O 298 /* on the named stream. The result value is the number of bytes 299 /* transferred. A short count is returned in case of end-of-file 300 /* or error conditions. 301 /* 302 /* vstream_fread_buf() resets the buffer write position, 303 /* allocates space for the specified number of bytes in the 304 /* buffer, reads the bytes from the specified VSTREAM, and 305 /* adjusts the buffer write position. The buffer is NOT 306 /* null-terminated. The result value is as with vstream_fread(). 307 /* NOTE: do not skip calling vstream_fread_buf() when len == 0. 308 /* This function has side effects including resetting the buffer 309 /* write position, and skipping the call would invalidate the 310 /* buffer state. 311 /* 312 /* vstream_fread_app() is like vstream_fread_buf() but appends 313 /* to existing buffer content, instead of writing over it. 314 /* 315 /* vstream_control() allows the user to fine tune the behavior of 316 /* the specified stream. The arguments are a list of macros with 317 /* zero or more arguments, terminated with CA_VSTREAM_CTL_END 318 /* which has none. The following lists the names and the types 319 /* of the corresponding value arguments. 320 /* .IP "CA_VSTREAM_CTL_READ_FN(ssize_t (*)(int, void *, size_t, int, void *))" 321 /* The argument specifies an alternative for the timed_read(3) function, 322 /* for example, a read function that performs decryption. 323 /* This function receives as arguments a file descriptor, buffer pointer, 324 /* buffer length, timeout value, and the VSTREAM's context value. 325 /* A timeout value <= 0 disables the time limit. 326 /* This function should return the positive number of bytes transferred, 327 /* 0 upon EOF, and -1 upon error with errno set appropriately. 328 /* .IP "CA_VSTREAM_CTL_WRITE_FN(ssize_t (*)(int, void *, size_t, int, void *))" 329 /* The argument specifies an alternative for the timed_write(3) function, 330 /* for example, a write function that performs encryption. 331 /* This function receives as arguments a file descriptor, buffer pointer, 332 /* buffer length, timeout value, and the VSTREAM's context value. 333 /* A timeout value <= 0 disables the time limit. 334 /* This function should return the positive number of bytes transferred, 335 /* and -1 upon error with errno set appropriately. Instead of -1 it may 336 /* also return 0, e.g., upon remote party-initiated protocol shutdown. 337 /* .IP "CA_VSTREAM_CTL_CONTEXT(void *)" 338 /* The argument specifies application context that is passed on to 339 /* the application-specified read/write routines. No copy is made. 340 /* .IP "CA_VSTREAM_CTL_PATH(const char *)" 341 /* Updates the stored pathname of the specified stream. The pathname 342 /* is copied. 343 /* .IP "CA_VSTREAM_CTL_DOUBLE (no arguments)" 344 /* Use separate buffers for reading and for writing. This prevents 345 /* unread input from being discarded upon change of I/O direction. 346 /* .IP "CA_VSTREAM_CTL_READ_FD(int)" 347 /* The argument specifies the file descriptor to be used for reading. 348 /* This feature is limited to double-buffered streams, and makes the 349 /* stream non-seekable. 350 /* .IP "CA_VSTREAM_CTL_WRITE_FD(int)" 351 /* The argument specifies the file descriptor to be used for writing. 352 /* This feature is limited to double-buffered streams, and makes the 353 /* stream non-seekable. 354 /* .IP "CA_VSTREAM_CTL_SWAP_FD(VSTREAM *)" 355 /* The argument specifies a VSTREAM pointer; the request swaps the 356 /* file descriptor members of the two streams. This feature is limited 357 /* to streams that are both double-buffered or both single-buffered. 358 /* .IP "CA_VSTREAM_CTL_DUPFD(int)" 359 /* The argument specifies a minimum file descriptor value. If 360 /* the actual stream's file descriptors are below the minimum, 361 /* reallocate the descriptors to the first free value greater 362 /* than or equal to the minimum. The VSTREAM_CTL_DUPFD macro 363 /* is defined only on systems with fcntl() F_DUPFD support. 364 /* .IP "CA_VSTREAM_CTL_WAITPID_FN(int (*)(pid_t, WAIT_STATUS_T *, int))" 365 /* A pointer to function that behaves like waitpid(). This information 366 /* is used by the vstream_pclose() routine. 367 /* .IP "CA_VSTREAM_CTL_TIMEOUT(int)" 368 /* The deadline for a descriptor to become readable in case of a read 369 /* request, or writable in case of a write request. Specify a value 370 /* of 0 to disable deadlines. 371 /* .IP "CA_VSTREAM_CTL_EXCEPT (no arguments)" 372 /* Enable exception handling with vstream_setjmp() and vstream_longjmp(). 373 /* This involves allocation of additional memory that normally isn't 374 /* used. 375 /* .IP "CA_VSTREAM_CTL_BUFSIZE(ssize_t)" 376 /* Specify a non-default buffer size for the next read(2) or 377 /* write(2) operation, or zero to implement a no-op. Requests 378 /* to reduce the buffer size are silently ignored (i.e. any 379 /* positive value <= vstream_req_bufsize()). To get a buffer 380 /* size smaller than VSTREAM_BUFSIZE, make the VSTREAM_CTL_BUFSIZE 381 /* request before the first stream read or write operation 382 /* (i.e., vstream_req_bufsize() returns zero). Requests to 383 /* change a fixed-size buffer (i.e., VSTREAM_ERR) are not 384 /* allowed. 385 /* 386 /* NOTE: the vstream_*printf() routines may silently expand a 387 /* buffer, so that the result of some %letter specifiers can 388 /* be written to contiguous memory. 389 /* .IP CA_VSTREAM_CTL_START_DEADLINE (no arguments) 390 /* Change the VSTREAM_CTL_TIMEOUT behavior, to a deadline for 391 /* the total amount of time for all subsequent file descriptor 392 /* read or write operations, and recharge the deadline timer. 393 /* .IP CA_VSTREAM_CTL_STOP_DEADLINE (no arguments) 394 /* Revert VSTREAM_CTL_TIMEOUT behavior to the default, i.e. 395 /* a time limit for individual file descriptor read or write 396 /* operations. 397 /* .IP CA_VSTREAM_CTL_MIN_DATA_RATE (int) 398 /* When the DEADLINE is enabled, the amount of data that must 399 /* be transferred to add 1 second to the deadline. However, 400 /* the deadline will never exceed the timeout specified with 401 /* VSTREAM_CTL_TIMEOUT. A zero value requests no update to the 402 /* deadline as data is transferred; that is appropriate for 403 /* request/reply interactions. 404 /* .IP CA_VSTREAM_CTL_OWN_VSTRING (no arguments) 405 /* Transfer ownership of the VSTRING that was opened with 406 /* vstream_memopen() etc. to the stream, so that the VSTRING 407 /* is automatically destroyed when the stream is closed. 408 /* .PP 409 /* vstream_fileno() gives access to the file handle associated with 410 /* a buffered stream. With streams that have separate read/write 411 /* file descriptors, the result is the current descriptor. 412 /* 413 /* vstream_req_bufsize() returns the buffer size that will be 414 /* used for the next read(2) or write(2) operation on the named 415 /* stream. A zero result means that the next read(2) or write(2) 416 /* operation will use the default buffer size (VSTREAM_BUFSIZE). 417 /* 418 /* vstream_context() returns the application context that is passed on to 419 /* the application-specified read/write routines. 420 /* 421 /* VSTREAM_PATH() is an unsafe macro that returns the name stored 422 /* with vstream_fopen() or with vstream_control(). The macro is 423 /* unsafe because it evaluates some arguments more than once. 424 /* 425 /* vstream_feof() returns non-zero when a previous operation on the 426 /* specified stream caused an end-of-file condition. 427 /* Although further read requests after EOF may complete 428 /* successfully, vstream_feof() will keep returning non-zero 429 /* until vstream_clearerr() is called for that stream. 430 /* 431 /* vstream_ferror() returns non-zero when a previous operation on the 432 /* specified stream caused a non-EOF error condition, including timeout. 433 /* After a non-EOF error on a stream, no I/O request will 434 /* complete until after vstream_clearerr() is called for that stream. 435 /* 436 /* vstream_ftimeout() returns non-zero when a previous operation on the 437 /* specified stream caused a timeout error condition. See 438 /* vstream_ferror() for error persistence details. 439 /* 440 /* vstream_clearerr() resets the timeout, error and end-of-file indication 441 /* of the specified stream, and returns no useful result. 442 /* 443 /* vstream_vfprintf() provides an alternate interface 444 /* for formatting an argument list according to a format string. 445 /* 446 /* vstream_vprintf() provides a similar alternative interface. 447 /* 448 /* vstream_bufstat() provides input and output buffer status 449 /* information. The command is one of the following: 450 /* .IP VSTREAM_BST_IN_PEND 451 /* Return the number of characters that can be read without 452 /* refilling the read buffer. 453 /* .IP VSTREAM_BST_OUT_PEND 454 /* Return the number of characters that are waiting in the 455 /* write buffer. 456 /* .PP 457 /* vstream_peek() returns the number of characters that can be 458 /* read from the named stream without refilling the read buffer. 459 /* This is an alias for vstream_bufstat(stream, VSTREAM_BST_IN_PEND). 460 /* 461 /* vstream_peek_data() returns a pointer to the unread bytes 462 /* that exist according to vstream_peek(), or null if no unread 463 /* bytes are available. 464 /* 465 /* vstream_setjmp() saves processing context and makes that context 466 /* available for use with vstream_longjmp(). Normally, vstream_setjmp() 467 /* returns zero. A non-zero result means that vstream_setjmp() returned 468 /* through a vstream_longjmp() call; the result is the \fIval\fR argument 469 /* given to vstream_longjmp(). 470 /* 471 /* NB: non-local jumps such as vstream_longjmp() are not safe 472 /* for jumping out of any routine that manipulates VSTREAM data. 473 /* longjmp() like calls are best avoided in signal handlers. 474 /* 475 /* vstream_ftime() returns the time of initialization, the last buffer 476 /* fill operation, or the last buffer flush operation for the specified 477 /* stream. This information is maintained only when stream timeouts are 478 /* enabled. 479 /* 480 /* vstream_ftimeval() is like vstream_ftime() but returns more 481 /* detail. 482 /* 483 /* vstream_rd_mumble() and vstream_wr_mumble() report on 484 /* read and write error conditions, respectively. 485 /* 486 /* vstream_fstat() queries stream status information about 487 /* user-requested features. The \fIflags\fR argument is the 488 /* bitwise OR of one or more of the following, and the result 489 /* value is the bitwise OR of the features that are activated. 490 /* .IP VSTREAM_FLAG_DEADLINE 491 /* The deadline feature is activated. 492 /* .IP VSTREAM_FLAG_DOUBLE 493 /* The double-buffering feature is activated. 494 /* .IP VSTREAM_FLAG_MEMORY 495 /* The stream is connected to a VSTRING buffer. 496 /* .IP VSTREAM_FLAG_OWN_VSTRING 497 /* The stream 'owns' the VSTRING buffer, and is responsible 498 /* for cleaning up when the stream is closed. 499 /* DIAGNOSTICS 500 /* Panics: interface violations. Fatal errors: out of memory. 501 /* SEE ALSO 502 /* timed_read(3) default read routine 503 /* timed_write(3) default write routine 504 /* vbuf_print(3) formatting engine 505 /* setjmp(3) non-local jumps 506 /* BUGS 507 /* Should use mmap() on reasonable systems. 508 /* LICENSE 509 /* .ad 510 /* .fi 511 /* The Secure Mailer license must be distributed with this software. 512 /* AUTHOR(S) 513 /* Wietse Venema 514 /* IBM T.J. Watson Research 515 /* P.O. Box 704 516 /* Yorktown Heights, NY 10598, USA 517 /* 518 /* Wietse Venema 519 /* Google, Inc. 520 /* 111 8th Avenue 521 /* New York, NY 10011, USA 522 /*--*/ 523 524 /* System library. */ 525 526 #include <sys_defs.h> 527 #include <stdlib.h> /* 44BSD stdarg.h uses abort() */ 528 #include <stdarg.h> 529 #include <stddef.h> 530 #include <unistd.h> 531 #include <fcntl.h> 532 #include <time.h> 533 #include <errno.h> 534 #include <string.h> 535 536 /* Utility library. */ 537 538 #define VSTRING_INTERNAL 539 540 #include "mymalloc.h" 541 #include "msg.h" 542 #include "vbuf_print.h" 543 #include "iostuff.h" 544 #include "vstring.h" 545 #include "vstream.h" 546 547 /* Application-specific. */ 548 549 /* 550 * Forward declarations. 551 */ 552 static int vstream_buf_get_ready(VBUF *); 553 static int vstream_buf_put_ready(VBUF *); 554 static int vstream_buf_space(VBUF *, ssize_t); 555 556 /* 557 * Initialization of the three pre-defined streams. Pre-allocate a static 558 * I/O buffer for the standard error stream, so that the error handler can 559 * produce a diagnostic even when memory allocation fails. 560 */ 561 static unsigned char vstream_fstd_buf[VSTREAM_BUFSIZE]; 562 563 VSTREAM vstream_fstd[] = { 564 {{ 565 0, /* flags */ 566 0, 0, 0, 0, /* buffer */ 567 vstream_buf_get_ready, vstream_buf_put_ready, vstream_buf_space, 568 }, STDIN_FILENO, (VSTREAM_RW_FN) timed_read, (VSTREAM_RW_FN) timed_write, 569 0,}, 570 {{ 571 0, /* flags */ 572 0, 0, 0, 0, /* buffer */ 573 vstream_buf_get_ready, vstream_buf_put_ready, vstream_buf_space, 574 }, STDOUT_FILENO, (VSTREAM_RW_FN) timed_read, (VSTREAM_RW_FN) timed_write, 575 0,}, 576 {{ 577 VBUF_FLAG_FIXED | VSTREAM_FLAG_WRITE, 578 vstream_fstd_buf, VSTREAM_BUFSIZE, VSTREAM_BUFSIZE, vstream_fstd_buf, 579 vstream_buf_get_ready, vstream_buf_put_ready, vstream_buf_space, 580 }, STDERR_FILENO, (VSTREAM_RW_FN) timed_read, (VSTREAM_RW_FN) timed_write, 581 VSTREAM_BUFSIZE,}, 582 }; 583 584 #define VSTREAM_STATIC(v) ((v) >= VSTREAM_IN && (v) <= VSTREAM_ERR) 585 586 /* 587 * A bunch of macros to make some expressions more readable. XXX We're 588 * assuming that O_RDONLY == 0, O_WRONLY == 1, O_RDWR == 2. 589 */ 590 #define VSTREAM_ACC_MASK(f) ((f) & (O_APPEND | O_WRONLY | O_RDWR)) 591 592 #define VSTREAM_CAN_READ(f) (VSTREAM_ACC_MASK(f) == O_RDONLY \ 593 || VSTREAM_ACC_MASK(f) == O_RDWR) 594 #define VSTREAM_CAN_WRITE(f) (VSTREAM_ACC_MASK(f) & O_WRONLY \ 595 || VSTREAM_ACC_MASK(f) & O_RDWR \ 596 || VSTREAM_ACC_MASK(f) & O_APPEND) 597 598 #define VSTREAM_BUF_COUNT(bp, n) \ 599 ((bp)->flags & VSTREAM_FLAG_READ ? -(n) : (n)) 600 601 #define VSTREAM_BUF_AT_START(bp) { \ 602 (bp)->cnt = VSTREAM_BUF_COUNT((bp), (bp)->len); \ 603 (bp)->ptr = (bp)->data; \ 604 } 605 606 #define VSTREAM_BUF_AT_OFFSET(bp, offset) { \ 607 (bp)->ptr = (bp)->data + (offset); \ 608 (bp)->cnt = VSTREAM_BUF_COUNT(bp, (bp)->len - (offset)); \ 609 } 610 611 #define VSTREAM_BUF_AT_END(bp) { \ 612 (bp)->cnt = 0; \ 613 (bp)->ptr = (bp)->data + (bp)->len; \ 614 } 615 616 #define VSTREAM_BUF_ZERO(bp) { \ 617 (bp)->flags = 0; \ 618 (bp)->data = (bp)->ptr = 0; \ 619 (bp)->len = (bp)->cnt = 0; \ 620 } 621 622 #define VSTREAM_BUF_ACTIONS(bp, get_action, put_action, space_action) { \ 623 (bp)->get_ready = (get_action); \ 624 (bp)->put_ready = (put_action); \ 625 (bp)->space = (space_action); \ 626 } 627 628 #define VSTREAM_SAVE_STATE(stream, buffer, filedes) { \ 629 stream->buffer = stream->buf; \ 630 stream->filedes = stream->fd; \ 631 } 632 633 #define VSTREAM_RESTORE_STATE(stream, buffer, filedes) do { \ 634 stream->buffer.flags = stream->buf.flags; \ 635 stream->buf = stream->buffer; \ 636 stream->fd = stream->filedes; \ 637 } while(0) 638 639 #define VSTREAM_FORK_STATE(stream, buffer, filedes) { \ 640 stream->buffer = stream->buf; \ 641 stream->filedes = stream->fd; \ 642 stream->buffer.data = stream->buffer.ptr = 0; \ 643 stream->buffer.len = stream->buffer.cnt = 0; \ 644 stream->buffer.flags &= ~VSTREAM_FLAG_FIXED; \ 645 }; 646 647 #define VSTREAM_FLAG_READ_DOUBLE (VSTREAM_FLAG_READ | VSTREAM_FLAG_DOUBLE) 648 #define VSTREAM_FLAG_WRITE_DOUBLE (VSTREAM_FLAG_WRITE | VSTREAM_FLAG_DOUBLE) 649 650 #define VSTREAM_FFLUSH_SOME(stream) \ 651 vstream_fflush_some((stream), (stream)->buf.len - (stream)->buf.cnt) 652 653 /* Note: this does not change a negative result into a zero result. */ 654 #define VSTREAM_SUB_TIME(x, y, z) \ 655 do { \ 656 (x).tv_sec = (y).tv_sec - (z).tv_sec; \ 657 (x).tv_usec = (y).tv_usec - (z).tv_usec; \ 658 while ((x).tv_usec < 0) { \ 659 (x).tv_usec += 1000000; \ 660 (x).tv_sec -= 1; \ 661 } \ 662 while ((x).tv_usec >= 1000000) { \ 663 (x).tv_usec -= 1000000; \ 664 (x).tv_sec += 1; \ 665 } \ 666 } while (0) 667 668 #define VSTREAM_ADD_TIME(x, y, z) \ 669 do { \ 670 (x).tv_sec = (y).tv_sec + (z).tv_sec; \ 671 (x).tv_usec = (y).tv_usec + (z).tv_usec; \ 672 while ((x).tv_usec >= 1000000) { \ 673 (x).tv_usec -= 1000000; \ 674 (x).tv_sec += 1; \ 675 } \ 676 } while (0) 677 678 /* vstream_buf_init - initialize buffer */ 679 680 static void vstream_buf_init(VBUF *bp, int flags) 681 { 682 683 /* 684 * Initialize the buffer such that the first data access triggers a 685 * buffer boundary action. 686 */ 687 VSTREAM_BUF_ZERO(bp); 688 VSTREAM_BUF_ACTIONS(bp, 689 VSTREAM_CAN_READ(flags) ? vstream_buf_get_ready : 0, 690 VSTREAM_CAN_WRITE(flags) ? vstream_buf_put_ready : 0, 691 vstream_buf_space); 692 } 693 694 /* vstream_buf_alloc - allocate buffer memory */ 695 696 static void vstream_buf_alloc(VBUF *bp, ssize_t len) 697 { 698 VSTREAM *stream = VBUF_TO_APPL(bp, VSTREAM, buf); 699 ssize_t used = bp->ptr - bp->data; 700 const char *myname = "vstream_buf_alloc"; 701 702 if (len < bp->len) 703 msg_panic("%s: attempt to shrink buffer", myname); 704 if (bp->flags & VSTREAM_FLAG_FIXED) 705 msg_panic("%s: unable to extend fixed-size buffer", myname); 706 707 /* 708 * Late buffer allocation allows the user to override the default policy. 709 * If a buffer already exists, allow for the presence of (output) data. 710 */ 711 bp->data = (unsigned char *) 712 (bp->data ? myrealloc((void *) bp->data, len) : mymalloc(len)); 713 if (bp->flags & VSTREAM_FLAG_MEMORY) 714 memset(bp->data + bp->len, 0, len - bp->len); 715 bp->len = len; 716 if (bp->flags & VSTREAM_FLAG_READ) { 717 bp->ptr = bp->data + used; 718 if (bp->flags & VSTREAM_FLAG_DOUBLE) 719 VSTREAM_SAVE_STATE(stream, read_buf, read_fd); 720 } else { 721 VSTREAM_BUF_AT_OFFSET(bp, used); 722 if (bp->flags & VSTREAM_FLAG_DOUBLE) 723 VSTREAM_SAVE_STATE(stream, write_buf, write_fd); 724 } 725 } 726 727 /* vstream_buf_wipe - reset buffer to initial state */ 728 729 static void vstream_buf_wipe(VBUF *bp) 730 { 731 if ((bp->flags & VBUF_FLAG_FIXED) == 0 && bp->data) 732 myfree((void *) bp->data); 733 VSTREAM_BUF_ZERO(bp); 734 VSTREAM_BUF_ACTIONS(bp, 0, 0, 0); 735 } 736 737 /* vstream_fflush_some - flush some buffered data */ 738 739 static int vstream_fflush_some(VSTREAM *stream, ssize_t to_flush) 740 { 741 const char *myname = "vstream_fflush_some"; 742 VBUF *bp = &stream->buf; 743 ssize_t used; 744 ssize_t left_over; 745 void *data; 746 ssize_t len; 747 ssize_t n; 748 int timeout; 749 struct timeval before; 750 struct timeval elapsed; 751 struct timeval bonus; 752 753 /* 754 * Sanity checks. It is illegal to flush a read-only stream. Otherwise, 755 * if there is buffered input, discard the input. If there is buffered 756 * output, require that the amount to flush is larger than the amount to 757 * keep, so that we can memcpy() the residue. 758 */ 759 if (bp->put_ready == 0) 760 msg_panic("%s: read-only stream", myname); 761 switch (bp->flags & (VSTREAM_FLAG_WRITE | VSTREAM_FLAG_READ)) { 762 case VSTREAM_FLAG_READ: /* discard input */ 763 VSTREAM_BUF_AT_END(bp); 764 /* FALLTHROUGH */ 765 case 0: /* flush after seek? */ 766 return ((bp->flags & VSTREAM_FLAG_ERR) ? VSTREAM_EOF : 0); 767 case VSTREAM_FLAG_WRITE: /* output buffered */ 768 break; 769 case VSTREAM_FLAG_WRITE | VSTREAM_FLAG_READ: 770 msg_panic("%s: read/write stream", myname); 771 } 772 used = bp->len - bp->cnt; 773 left_over = used - to_flush; 774 775 if (msg_verbose > 2 && stream != VSTREAM_ERR) 776 msg_info("%s: fd %d flush %ld", myname, stream->fd, (long) to_flush); 777 if (to_flush < 0 || left_over < 0) 778 msg_panic("%s: bad to_flush %ld", myname, (long) to_flush); 779 if (to_flush < left_over) 780 msg_panic("%s: to_flush < left_over", myname); 781 if (to_flush == 0) 782 return ((bp->flags & VSTREAM_FLAG_ERR) ? VSTREAM_EOF : 0); 783 if (bp->flags & VSTREAM_FLAG_ERR) 784 return (VSTREAM_EOF); 785 786 /* 787 * When flushing a buffer, allow for partial writes. These can happen 788 * while talking to a network. Update the cached file seek position, if 789 * any. 790 * 791 * When deadlines are enabled, we count the elapsed time for each write 792 * operation instead of simply comparing the time-of-day clock with a 793 * per-stream deadline. The latter could result in anomalies when an 794 * application does lengthy processing between write operations. Keep in 795 * mind that a receiver may not be able to keep up when a sender suddenly 796 * floods it with a lot of data as it tries to catch up with a deadline. 797 */ 798 for (data = (void *) bp->data, len = to_flush; len > 0; len -= n, data += n) { 799 if (bp->flags & VSTREAM_FLAG_DEADLINE) { 800 timeout = stream->time_limit.tv_sec + (stream->time_limit.tv_usec > 0); 801 if (timeout <= 0) { 802 bp->flags |= (VSTREAM_FLAG_WR_ERR | VSTREAM_FLAG_WR_TIMEOUT); 803 errno = ETIMEDOUT; 804 return (VSTREAM_EOF); 805 } 806 if (len == to_flush) 807 GETTIMEOFDAY(&before); 808 else 809 before = stream->iotime; 810 } else 811 timeout = stream->timeout; 812 if ((n = stream->write_fn(stream->fd, data, len, timeout, stream->context)) <= 0) { 813 bp->flags |= VSTREAM_FLAG_WR_ERR; 814 if (errno == ETIMEDOUT) { 815 bp->flags |= VSTREAM_FLAG_WR_TIMEOUT; 816 stream->time_limit.tv_sec = stream->time_limit.tv_usec = 0; 817 } 818 return (VSTREAM_EOF); 819 } 820 if (timeout) { 821 GETTIMEOFDAY(&stream->iotime); 822 if (bp->flags & VSTREAM_FLAG_DEADLINE) { 823 VSTREAM_SUB_TIME(elapsed, stream->iotime, before); 824 VSTREAM_SUB_TIME(stream->time_limit, stream->time_limit, elapsed); 825 if (stream->min_data_rate > 0) { 826 bonus.tv_sec = n / stream->min_data_rate; 827 bonus.tv_usec = (n % stream->min_data_rate) * 1000000; 828 bonus.tv_usec /= stream->min_data_rate; 829 VSTREAM_ADD_TIME(stream->time_limit, stream->time_limit, 830 bonus); 831 if (stream->time_limit.tv_sec >= stream->timeout) { 832 stream->time_limit.tv_sec = stream->timeout; 833 stream->time_limit.tv_usec = 0; 834 } 835 } 836 } 837 } 838 if (msg_verbose > 2 && stream != VSTREAM_ERR && n != to_flush) 839 msg_info("%s: %d flushed %ld/%ld", myname, stream->fd, 840 (long) n, (long) to_flush); 841 } 842 if (bp->flags & VSTREAM_FLAG_SEEK) 843 stream->offset += to_flush; 844 845 /* 846 * Allow for partial buffer flush requests. We use memcpy() for reasons 847 * of portability to pre-ANSI environments (SunOS 4.x or Ultrix 4.x :-). 848 * This is OK because we have already verified that the to_flush count is 849 * larger than the left_over count. 850 */ 851 if (left_over > 0) 852 memcpy(bp->data, bp->data + to_flush, left_over); 853 bp->cnt += to_flush; 854 bp->ptr -= to_flush; 855 return ((bp->flags & VSTREAM_FLAG_ERR) ? VSTREAM_EOF : 0); 856 } 857 858 /* vstream_fflush_delayed - delayed stream flush for double-buffered stream */ 859 860 static int vstream_fflush_delayed(VSTREAM *stream) 861 { 862 int status; 863 864 /* 865 * Sanity check. 866 */ 867 if ((stream->buf.flags & VSTREAM_FLAG_READ_DOUBLE) != VSTREAM_FLAG_READ_DOUBLE) 868 msg_panic("vstream_fflush_delayed: bad flags"); 869 870 /* 871 * Temporarily swap buffers and flush unwritten data. This may seem like 872 * a lot of work, but it's peanuts compared to the write(2) call that we 873 * already have avoided. For example, delayed flush is never used on a 874 * non-pipelined SMTP connection. 875 */ 876 stream->buf.flags &= ~VSTREAM_FLAG_READ; 877 VSTREAM_SAVE_STATE(stream, read_buf, read_fd); 878 stream->buf.flags |= VSTREAM_FLAG_WRITE; 879 VSTREAM_RESTORE_STATE(stream, write_buf, write_fd); 880 881 status = VSTREAM_FFLUSH_SOME(stream); 882 883 stream->buf.flags &= ~VSTREAM_FLAG_WRITE; 884 VSTREAM_SAVE_STATE(stream, write_buf, write_fd); 885 stream->buf.flags |= VSTREAM_FLAG_READ; 886 VSTREAM_RESTORE_STATE(stream, read_buf, read_fd); 887 888 return (status); 889 } 890 891 /* vstream_buf_get_ready - vbuf callback to make buffer ready for reading */ 892 893 static int vstream_buf_get_ready(VBUF *bp) 894 { 895 VSTREAM *stream = VBUF_TO_APPL(bp, VSTREAM, buf); 896 const char *myname = "vstream_buf_get_ready"; 897 ssize_t n; 898 struct timeval before; 899 struct timeval elapsed; 900 struct timeval bonus; 901 int timeout; 902 903 /* 904 * Detect a change of I/O direction or position. If so, flush any 905 * unwritten output immediately when the stream is single-buffered, or 906 * when the stream is double-buffered and the read buffer is empty. 907 */ 908 switch (bp->flags & (VSTREAM_FLAG_WRITE | VSTREAM_FLAG_READ)) { 909 case VSTREAM_FLAG_WRITE: /* change direction */ 910 if (bp->ptr > bp->data) 911 if ((bp->flags & VSTREAM_FLAG_DOUBLE) == 0 912 || stream->read_buf.cnt >= 0) 913 if (VSTREAM_FFLUSH_SOME(stream)) 914 return (VSTREAM_EOF); 915 bp->flags &= ~VSTREAM_FLAG_WRITE; 916 if (bp->flags & VSTREAM_FLAG_DOUBLE) 917 VSTREAM_SAVE_STATE(stream, write_buf, write_fd); 918 /* FALLTHROUGH */ 919 case 0: /* change position */ 920 bp->flags |= VSTREAM_FLAG_READ; 921 if (bp->flags & VSTREAM_FLAG_DOUBLE) { 922 VSTREAM_RESTORE_STATE(stream, read_buf, read_fd); 923 if (bp->cnt < 0) 924 return (0); 925 } 926 /* FALLTHROUGH */ 927 case VSTREAM_FLAG_READ: /* no change */ 928 break; 929 case VSTREAM_FLAG_WRITE | VSTREAM_FLAG_READ: 930 msg_panic("%s: read/write stream", myname); 931 } 932 933 /* 934 * If this is the first GET operation, allocate a buffer. Late buffer 935 * allocation gives the application a chance to override the default 936 * buffering policy. 937 * 938 * XXX Subtle code to set the preferred buffer size as late as possible. 939 */ 940 if (stream->req_bufsize == 0) 941 stream->req_bufsize = VSTREAM_BUFSIZE; 942 if (bp->len < stream->req_bufsize) 943 vstream_buf_alloc(bp, stream->req_bufsize); 944 945 /* 946 * If the stream is double-buffered and the write buffer is not empty, 947 * this is the time to flush the write buffer. Delayed flushes reduce 948 * system call overhead, and on TCP sockets, avoid triggering Nagle's 949 * algorithm. 950 */ 951 if ((bp->flags & VSTREAM_FLAG_DOUBLE) 952 && stream->write_buf.len > stream->write_buf.cnt) 953 if (vstream_fflush_delayed(stream)) 954 return (VSTREAM_EOF); 955 956 /* 957 * Did we receive an EOF indication? 958 */ 959 if (bp->flags & VSTREAM_FLAG_EOF) 960 return (VSTREAM_EOF); 961 962 /* 963 * Fill the buffer with as much data as we can handle, or with as much 964 * data as is available right now, whichever is less. Update the cached 965 * file seek position, if any. 966 * 967 * When deadlines are enabled, we count the elapsed time for each read 968 * operation instead of simply comparing the time-of-day clock with a 969 * per-stream deadline. The latter could result in anomalies when an 970 * application does lengthy processing between read operations. Keep in 971 * mind that a sender may get blocked, and may not be able to keep up 972 * when a receiver suddenly wants to read a lot of data as it tries to 973 * catch up with a deadline. 974 */ 975 if (bp->flags & VSTREAM_FLAG_DEADLINE) { 976 timeout = stream->time_limit.tv_sec + (stream->time_limit.tv_usec > 0); 977 if (timeout <= 0) { 978 bp->flags |= (VSTREAM_FLAG_RD_ERR | VSTREAM_FLAG_RD_TIMEOUT); 979 errno = ETIMEDOUT; 980 return (VSTREAM_EOF); 981 } 982 GETTIMEOFDAY(&before); 983 } else 984 timeout = stream->timeout; 985 switch (n = stream->read_fn(stream->fd, bp->data, bp->len, timeout, stream->context)) { 986 case -1: 987 bp->flags |= VSTREAM_FLAG_RD_ERR; 988 if (errno == ETIMEDOUT) { 989 bp->flags |= VSTREAM_FLAG_RD_TIMEOUT; 990 stream->time_limit.tv_sec = stream->time_limit.tv_usec = 0; 991 } 992 return (VSTREAM_EOF); 993 case 0: 994 bp->flags |= VSTREAM_FLAG_EOF; 995 return (VSTREAM_EOF); 996 default: 997 if (timeout) { 998 GETTIMEOFDAY(&stream->iotime); 999 if (bp->flags & VSTREAM_FLAG_DEADLINE) { 1000 VSTREAM_SUB_TIME(elapsed, stream->iotime, before); 1001 VSTREAM_SUB_TIME(stream->time_limit, stream->time_limit, elapsed); 1002 if (stream->min_data_rate > 0) { 1003 bonus.tv_sec = n / stream->min_data_rate; 1004 bonus.tv_usec = (n % stream->min_data_rate) * 1000000; 1005 bonus.tv_usec /= stream->min_data_rate; 1006 VSTREAM_ADD_TIME(stream->time_limit, stream->time_limit, 1007 bonus); 1008 if (stream->time_limit.tv_sec >= stream->timeout) { 1009 stream->time_limit.tv_sec = stream->timeout; 1010 stream->time_limit.tv_usec = 0; 1011 } 1012 } 1013 } 1014 } 1015 if (msg_verbose > 2) 1016 msg_info("%s: fd %d got %ld", myname, stream->fd, (long) n); 1017 bp->cnt = -n; 1018 bp->ptr = bp->data; 1019 if (bp->flags & VSTREAM_FLAG_SEEK) 1020 stream->offset += n; 1021 return (0); 1022 } 1023 } 1024 1025 /* vstream_buf_put_ready - vbuf callback to make buffer ready for writing */ 1026 1027 static int vstream_buf_put_ready(VBUF *bp) 1028 { 1029 VSTREAM *stream = VBUF_TO_APPL(bp, VSTREAM, buf); 1030 const char *myname = "vstream_buf_put_ready"; 1031 1032 /* 1033 * Sanity checks. Detect a change of I/O direction or position. If so, 1034 * discard unread input, and reset the buffer to the beginning. 1035 */ 1036 switch (bp->flags & (VSTREAM_FLAG_WRITE | VSTREAM_FLAG_READ)) { 1037 case VSTREAM_FLAG_READ: /* change direction */ 1038 bp->flags &= ~VSTREAM_FLAG_READ; 1039 if (bp->flags & VSTREAM_FLAG_DOUBLE) 1040 VSTREAM_SAVE_STATE(stream, read_buf, read_fd); 1041 /* FALLTHROUGH */ 1042 case 0: /* change position */ 1043 bp->flags |= VSTREAM_FLAG_WRITE; 1044 if (bp->flags & VSTREAM_FLAG_DOUBLE) 1045 VSTREAM_RESTORE_STATE(stream, write_buf, write_fd); 1046 else 1047 VSTREAM_BUF_AT_START(bp); 1048 /* FALLTHROUGH */ 1049 case VSTREAM_FLAG_WRITE: /* no change */ 1050 break; 1051 case VSTREAM_FLAG_WRITE | VSTREAM_FLAG_READ: 1052 msg_panic("%s: read/write stream", myname); 1053 } 1054 1055 /* 1056 * Remember the direction. If this is the first PUT operation for this 1057 * stream or if the buffer is smaller than the requested size, allocate a 1058 * new buffer; obviously there is no data to be flushed yet. Otherwise, 1059 * flush the buffer. 1060 * 1061 * XXX Subtle code to set the preferred buffer size as late as possible. 1062 */ 1063 if (stream->req_bufsize == 0) 1064 stream->req_bufsize = VSTREAM_BUFSIZE; 1065 if (bp->len < stream->req_bufsize) { 1066 vstream_buf_alloc(bp, stream->req_bufsize); 1067 } else if (bp->cnt <= 0) { 1068 if (VSTREAM_FFLUSH_SOME(stream)) 1069 return (VSTREAM_EOF); 1070 } 1071 return (0); 1072 } 1073 1074 /* vstream_buf_space - reserve space ahead of time */ 1075 1076 static int vstream_buf_space(VBUF *bp, ssize_t want) 1077 { 1078 VSTREAM *stream = VBUF_TO_APPL(bp, VSTREAM, buf); 1079 ssize_t used; 1080 ssize_t incr; 1081 ssize_t shortage; 1082 const char *myname = "vstream_buf_space"; 1083 1084 /* 1085 * Sanity checks. Reserving space implies writing. It is illegal to write 1086 * to a read-only stream. Detect a change of I/O direction or position. 1087 * If so, reset the buffer to the beginning. 1088 */ 1089 if (bp->put_ready == 0) 1090 msg_panic("%s: read-only stream", myname); 1091 if (want < 0) 1092 msg_panic("%s: bad length %ld", myname, (long) want); 1093 switch (bp->flags & (VSTREAM_FLAG_READ | VSTREAM_FLAG_WRITE)) { 1094 case VSTREAM_FLAG_READ: /* change direction */ 1095 bp->flags &= ~VSTREAM_FLAG_READ; 1096 if (bp->flags & VSTREAM_FLAG_DOUBLE) 1097 VSTREAM_SAVE_STATE(stream, read_buf, read_fd); 1098 /* FALLTHROUGH */ 1099 case 0: /* change position */ 1100 bp->flags |= VSTREAM_FLAG_WRITE; 1101 if (bp->flags & VSTREAM_FLAG_DOUBLE) 1102 VSTREAM_RESTORE_STATE(stream, write_buf, write_fd); 1103 else 1104 VSTREAM_BUF_AT_START(bp); 1105 /* FALLTHROUGH */ 1106 case VSTREAM_FLAG_WRITE: /* no change */ 1107 break; 1108 case VSTREAM_FLAG_READ | VSTREAM_FLAG_WRITE: 1109 msg_panic("%s: read/write stream", myname); 1110 } 1111 1112 /* 1113 * See if enough space is available. If not, flush a multiple of 1114 * VSTREAM_BUFSIZE bytes and resize the buffer to a multiple of 1115 * VSTREAM_BUFSIZE. We flush multiples of VSTREAM_BUFSIZE in an attempt 1116 * to keep file updates block-aligned for better performance. 1117 * 1118 * XXX Subtle code to set the preferred buffer size as late as possible. 1119 */ 1120 #define VSTREAM_TRUNCATE(count, base) (((count) / (base)) * (base)) 1121 #define VSTREAM_ROUNDUP(count, base) VSTREAM_TRUNCATE(count + base - 1, base) 1122 1123 if (stream->req_bufsize == 0) 1124 stream->req_bufsize = VSTREAM_BUFSIZE; 1125 if (want > bp->cnt) { 1126 if ((used = bp->len - bp->cnt) > stream->req_bufsize) 1127 if (vstream_fflush_some(stream, VSTREAM_TRUNCATE(used, stream->req_bufsize))) 1128 return (VSTREAM_EOF); 1129 if ((shortage = (want - bp->cnt)) > 0) { 1130 if ((bp->flags & VSTREAM_FLAG_FIXED) 1131 || shortage > __MAXINT__(ssize_t) -bp->len - stream->req_bufsize) { 1132 bp->flags |= VSTREAM_FLAG_WR_ERR; 1133 } else { 1134 incr = VSTREAM_ROUNDUP(shortage, stream->req_bufsize); 1135 vstream_buf_alloc(bp, bp->len + incr); 1136 } 1137 } 1138 } 1139 return (vstream_ferror(stream) ? VSTREAM_EOF : 0); /* mmap() may fail */ 1140 } 1141 1142 /* vstream_fpurge - discard unread or unwritten content */ 1143 1144 int vstream_fpurge(VSTREAM *stream, int direction) 1145 { 1146 const char *myname = "vstream_fpurge"; 1147 VBUF *bp = &stream->buf; 1148 1149 #define VSTREAM_MAYBE_PURGE_WRITE(d, b) if ((d) & VSTREAM_PURGE_WRITE) \ 1150 VSTREAM_BUF_AT_START((b)) 1151 #define VSTREAM_MAYBE_PURGE_READ(d, b) if ((d) & VSTREAM_PURGE_READ) \ 1152 VSTREAM_BUF_AT_END((b)) 1153 1154 /* 1155 * To discard all unread contents, position the read buffer at its end, 1156 * so that we skip over any unread data, and so that the next read 1157 * operation will refill the buffer. 1158 * 1159 * To discard all unwritten content, position the write buffer at its 1160 * beginning, so that the next write operation clobbers any unwritten 1161 * data. 1162 */ 1163 switch (bp->flags & (VSTREAM_FLAG_READ_DOUBLE | VSTREAM_FLAG_WRITE)) { 1164 case VSTREAM_FLAG_READ_DOUBLE: 1165 VSTREAM_MAYBE_PURGE_WRITE(direction, &stream->write_buf); 1166 /* FALLTHROUGH */ 1167 case VSTREAM_FLAG_READ: 1168 VSTREAM_MAYBE_PURGE_READ(direction, bp); 1169 break; 1170 case VSTREAM_FLAG_DOUBLE: 1171 VSTREAM_MAYBE_PURGE_WRITE(direction, &stream->write_buf); 1172 VSTREAM_MAYBE_PURGE_READ(direction, &stream->read_buf); 1173 break; 1174 case VSTREAM_FLAG_WRITE_DOUBLE: 1175 VSTREAM_MAYBE_PURGE_READ(direction, &stream->read_buf); 1176 /* FALLTHROUGH */ 1177 case VSTREAM_FLAG_WRITE: 1178 VSTREAM_MAYBE_PURGE_WRITE(direction, bp); 1179 break; 1180 case VSTREAM_FLAG_READ_DOUBLE | VSTREAM_FLAG_WRITE: 1181 case VSTREAM_FLAG_READ | VSTREAM_FLAG_WRITE: 1182 msg_panic("%s: read/write stream", myname); 1183 } 1184 1185 /* 1186 * Invalidate the cached file seek position. 1187 */ 1188 bp->flags &= ~VSTREAM_FLAG_SEEK; 1189 stream->offset = 0; 1190 1191 return (0); 1192 } 1193 1194 /* vstream_fseek - change I/O position */ 1195 1196 off_t vstream_fseek(VSTREAM *stream, off_t offset, int whence) 1197 { 1198 const char *myname = "vstream_fseek"; 1199 VBUF *bp = &stream->buf; 1200 1201 /* 1202 * TODO: support data length (data length != buffer length). Without data 1203 * length information, Without explicit data length information, 1204 * vstream_memopen(O_RDONLY) has to set the VSTREAM buffer length to the 1205 * vstring payload length to avoid accessing unwritten data after 1206 * vstream_fseek(), because for lseek() compatibility, vstream_fseek() 1207 * must allow seeking past the end of a file. 1208 */ 1209 if (stream->buf.flags & VSTREAM_FLAG_MEMORY) { 1210 if (whence == SEEK_CUR) 1211 offset += (bp->ptr - bp->data); 1212 else if (whence == SEEK_END) 1213 offset += bp->len; 1214 if (offset < 0) { 1215 errno = EINVAL; 1216 return (-1); 1217 } 1218 if (offset > bp->len && (bp->flags & VSTREAM_FLAG_WRITE)) 1219 vstream_buf_space(bp, offset - bp->len); 1220 VSTREAM_BUF_AT_OFFSET(bp, offset); 1221 return (offset); 1222 } 1223 1224 /* 1225 * Flush any unwritten output. Discard any unread input. Position the 1226 * buffer at the end, so that the next GET or PUT operation triggers a 1227 * buffer boundary action. 1228 */ 1229 switch (bp->flags & (VSTREAM_FLAG_READ | VSTREAM_FLAG_WRITE)) { 1230 case VSTREAM_FLAG_WRITE: 1231 if (bp->ptr > bp->data) { 1232 if (whence == SEEK_CUR) 1233 offset += (bp->ptr - bp->data); /* add unwritten data */ 1234 else if (whence == SEEK_END) 1235 bp->flags &= ~VSTREAM_FLAG_SEEK; 1236 if (VSTREAM_FFLUSH_SOME(stream)) 1237 return (-1); 1238 } 1239 VSTREAM_BUF_AT_END(bp); 1240 break; 1241 case VSTREAM_FLAG_READ: 1242 if (whence == SEEK_CUR) 1243 offset += bp->cnt; /* subtract unread data */ 1244 else if (whence == SEEK_END) 1245 bp->flags &= ~VSTREAM_FLAG_SEEK; 1246 /* FALLTHROUGH */ 1247 case 0: 1248 VSTREAM_BUF_AT_END(bp); 1249 break; 1250 case VSTREAM_FLAG_READ | VSTREAM_FLAG_WRITE: 1251 msg_panic("%s: read/write stream", myname); 1252 } 1253 1254 /* 1255 * Clear the read/write flags to inform the buffer boundary action 1256 * routines that we may have changed I/O position. 1257 */ 1258 bp->flags &= ~(VSTREAM_FLAG_READ | VSTREAM_FLAG_WRITE); 1259 1260 /* 1261 * Shave an unnecessary system call. 1262 */ 1263 if (bp->flags & VSTREAM_FLAG_NSEEK) { 1264 errno = ESPIPE; 1265 return (-1); 1266 } 1267 1268 /* 1269 * Update the cached file seek position. 1270 */ 1271 if ((stream->offset = lseek(stream->fd, offset, whence)) < 0) { 1272 if (errno == ESPIPE) 1273 bp->flags |= VSTREAM_FLAG_NSEEK; 1274 } else { 1275 bp->flags |= VSTREAM_FLAG_SEEK; 1276 } 1277 bp->flags &= ~VSTREAM_FLAG_EOF; 1278 return (stream->offset); 1279 } 1280 1281 /* vstream_ftell - return file offset */ 1282 1283 off_t vstream_ftell(VSTREAM *stream) 1284 { 1285 VBUF *bp = &stream->buf; 1286 1287 /* 1288 * Special case for memory buffer. 1289 */ 1290 if (stream->buf.flags & VSTREAM_FLAG_MEMORY) 1291 return (bp->ptr - bp->data); 1292 1293 /* 1294 * Shave an unnecessary syscall. 1295 */ 1296 if (bp->flags & VSTREAM_FLAG_NSEEK) { 1297 errno = ESPIPE; 1298 return (-1); 1299 } 1300 1301 /* 1302 * Use the cached file offset when available. This is the offset after 1303 * the last read, write or seek operation. 1304 */ 1305 if ((bp->flags & VSTREAM_FLAG_SEEK) == 0) { 1306 if ((stream->offset = lseek(stream->fd, (off_t) 0, SEEK_CUR)) < 0) { 1307 bp->flags |= VSTREAM_FLAG_NSEEK; 1308 return (-1); 1309 } 1310 bp->flags |= VSTREAM_FLAG_SEEK; 1311 } 1312 1313 /* 1314 * If this is a read buffer, subtract the number of unread bytes from the 1315 * cached offset. Remember that read counts are negative. 1316 */ 1317 if (bp->flags & VSTREAM_FLAG_READ) 1318 return (stream->offset + bp->cnt); 1319 1320 /* 1321 * If this is a write buffer, add the number of unwritten bytes to the 1322 * cached offset. 1323 */ 1324 if (bp->flags & VSTREAM_FLAG_WRITE) 1325 return (stream->offset + (bp->ptr - bp->data)); 1326 1327 /* 1328 * Apparently, this is a new buffer, or a buffer after seek, so there is 1329 * no need to account for unread or unwritten data. 1330 */ 1331 return (stream->offset); 1332 } 1333 1334 /* vstream_subopen - initialize everything except buffers and I/O handlers */ 1335 1336 static VSTREAM *vstream_subopen(void) 1337 { 1338 VSTREAM *stream; 1339 1340 /* Note: memset() is not a portable way to initialize non-integer types. */ 1341 stream = (VSTREAM *) mymalloc(sizeof(*stream)); 1342 stream->offset = 0; 1343 stream->path = 0; 1344 stream->pid = 0; 1345 stream->waitpid_fn = 0; 1346 stream->timeout = 0; 1347 stream->context = 0; 1348 stream->jbuf = 0; 1349 stream->iotime.tv_sec = stream->iotime.tv_usec = 0; 1350 stream->time_limit.tv_sec = stream->time_limit.tv_usec = 0; 1351 stream->req_bufsize = 0; 1352 stream->vstring = 0; 1353 stream->min_data_rate = 0; 1354 return (stream); 1355 } 1356 1357 /* vstream_fdopen - add buffering to pre-opened stream */ 1358 1359 VSTREAM *vstream_fdopen(int fd, int flags) 1360 { 1361 VSTREAM *stream; 1362 1363 /* 1364 * Sanity check. 1365 */ 1366 if (fd < 0) 1367 msg_panic("vstream_fdopen: bad file %d", fd); 1368 1369 /* 1370 * Initialize buffers etc. but do as little as possible. Late buffer 1371 * allocation etc. gives the application a chance to override default 1372 * policies. Either this, or the vstream*open() routines would have to 1373 * have a really ugly interface with lots of mostly-unused arguments (can 1374 * you say VMS?). 1375 */ 1376 stream = vstream_subopen(); 1377 stream->fd = fd; 1378 stream->read_fn = VSTREAM_CAN_READ(flags) ? (VSTREAM_RW_FN) timed_read : 0; 1379 stream->write_fn = VSTREAM_CAN_WRITE(flags) ? (VSTREAM_RW_FN) timed_write : 0; 1380 vstream_buf_init(&stream->buf, flags); 1381 return (stream); 1382 } 1383 1384 /* vstream_fopen - open buffered file stream */ 1385 1386 VSTREAM *vstream_fopen(const char *path, int flags, mode_t mode) 1387 { 1388 VSTREAM *stream; 1389 int fd; 1390 1391 if ((fd = open(path, flags, mode)) < 0) { 1392 return (0); 1393 } else { 1394 stream = vstream_fdopen(fd, flags); 1395 stream->path = mystrdup(path); 1396 return (stream); 1397 } 1398 } 1399 1400 /* vstream_fflush - flush write buffer */ 1401 1402 int vstream_fflush(VSTREAM *stream) 1403 { 1404 1405 /* 1406 * With VSTRING, the write pointer must be positioned behind the end of 1407 * data. But vstream_fseek() changes the write position, and causes the 1408 * data length to be forgotten. Before flushing to vstream, remember the 1409 * current write position, move the write pointer and do what needs to be 1410 * done, then move the write pointer back to the saved location. 1411 */ 1412 if (stream->buf.flags & VSTREAM_FLAG_MEMORY) { 1413 if (stream->buf.flags & VSTREAM_FLAG_WRITE) { 1414 VSTRING *string = stream->vstring; 1415 1416 #ifdef PENDING_VSTREAM_FSEEK_FOR_MEMORY 1417 VSTREAM_BUF_AT_OFFSET(&stream->buf, stream->buf.data_len); 1418 #endif 1419 memcpy(&string->vbuf, &stream->buf, sizeof(stream->buf)); 1420 string->vbuf.flags &= VSTRING_FLAG_MASK; 1421 VSTRING_TERMINATE(string); 1422 } 1423 return (0); 1424 } 1425 if ((stream->buf.flags & VSTREAM_FLAG_READ_DOUBLE) 1426 == VSTREAM_FLAG_READ_DOUBLE 1427 && stream->write_buf.len > stream->write_buf.cnt) 1428 vstream_fflush_delayed(stream); 1429 return (VSTREAM_FFLUSH_SOME(stream)); 1430 } 1431 1432 /* vstream_fclose - close buffered stream */ 1433 1434 int vstream_fclose(VSTREAM *stream) 1435 { 1436 int err; 1437 1438 /* 1439 * NOTE: Negative file descriptors are not part of the external 1440 * interface. They are for internal use only, in order to support 1441 * vstream_fdclose() without a lot of code duplication. Applications that 1442 * rely on negative VSTREAM file descriptors will break without warning. 1443 */ 1444 if (stream->pid != 0) 1445 msg_panic("vstream_fclose: stream has process"); 1446 if ((stream->buf.flags & VSTREAM_FLAG_MEMORY) 1447 || ((stream->buf.flags & VSTREAM_FLAG_WRITE_DOUBLE) != 0 1448 && stream->fd >= 0)) 1449 vstream_fflush(stream); 1450 /* Do not remove: vstream_fdclose() depends on this error test. */ 1451 err = vstream_ferror(stream); 1452 if (stream->buf.flags & VSTREAM_FLAG_DOUBLE) { 1453 if (stream->read_fd >= 0) 1454 err |= close(stream->read_fd); 1455 if (stream->write_fd != stream->read_fd) 1456 if (stream->write_fd >= 0) 1457 err |= close(stream->write_fd); 1458 vstream_buf_wipe(&stream->read_buf); 1459 vstream_buf_wipe(&stream->write_buf); 1460 stream->buf = stream->read_buf; 1461 } else { 1462 if (stream->fd >= 0) 1463 err |= close(stream->fd); 1464 if ((stream->buf.flags & VSTREAM_FLAG_MEMORY) == 0) 1465 vstream_buf_wipe(&stream->buf); 1466 } 1467 if (stream->path) 1468 myfree(stream->path); 1469 if (stream->jbuf) 1470 myfree((void *) stream->jbuf); 1471 if (stream->vstring && (stream->buf.flags & VSTREAM_FLAG_OWN_VSTRING)) 1472 vstring_free(stream->vstring); 1473 if (!VSTREAM_STATIC(stream)) 1474 myfree((void *) stream); 1475 return (err ? VSTREAM_EOF : 0); 1476 } 1477 1478 /* vstream_fdclose - close stream, leave file(s) open */ 1479 1480 int vstream_fdclose(VSTREAM *stream) 1481 { 1482 1483 /* 1484 * Flush unwritten output, just like vstream_fclose(). Errors are 1485 * reported by vstream_fclose(). 1486 */ 1487 if ((stream->buf.flags & VSTREAM_FLAG_WRITE_DOUBLE) != 0) 1488 (void) vstream_fflush(stream); 1489 1490 /* 1491 * NOTE: Negative file descriptors are not part of the external 1492 * interface. They are for internal use only, in order to support 1493 * vstream_fdclose() without a lot of code duplication. Applications that 1494 * rely on negative VSTREAM file descriptors will break without warning. 1495 */ 1496 if (stream->buf.flags & VSTREAM_FLAG_DOUBLE) { 1497 stream->fd = stream->read_fd = stream->write_fd = -1; 1498 } else { 1499 stream->fd = -1; 1500 } 1501 return (vstream_fclose(stream)); 1502 } 1503 1504 /* vstream_printf - formatted print to stdout */ 1505 1506 VSTREAM *vstream_printf(const char *fmt,...) 1507 { 1508 VSTREAM *stream = VSTREAM_OUT; 1509 va_list ap; 1510 1511 va_start(ap, fmt); 1512 vbuf_print(&stream->buf, fmt, ap); 1513 va_end(ap); 1514 return (stream); 1515 } 1516 1517 /* vstream_fprintf - formatted print to buffered stream */ 1518 1519 VSTREAM *vstream_fprintf(VSTREAM *stream, const char *fmt,...) 1520 { 1521 va_list ap; 1522 1523 va_start(ap, fmt); 1524 vbuf_print(&stream->buf, fmt, ap); 1525 va_end(ap); 1526 return (stream); 1527 } 1528 1529 /* vstream_fputs - write string to stream */ 1530 1531 int vstream_fputs(const char *str, VSTREAM *stream) 1532 { 1533 int ch; 1534 1535 while ((ch = *str++) != 0) 1536 if (VSTREAM_PUTC(ch, stream) == VSTREAM_EOF) 1537 return (VSTREAM_EOF); 1538 return (0); 1539 } 1540 1541 /* vstream_fread_buf - unformatted read to VSTRING */ 1542 1543 ssize_t vstream_fread_buf(VSTREAM *fp, VSTRING *vp, ssize_t len) 1544 { 1545 ssize_t ret; 1546 1547 VSTRING_RESET(vp); 1548 VSTRING_SPACE(vp, len); 1549 ret = vstream_fread(fp, vstring_str(vp), len); 1550 if (ret > 0) 1551 VSTRING_AT_OFFSET(vp, ret); 1552 return (ret); 1553 } 1554 1555 /* vstream_fread_app - unformatted read to VSTRING */ 1556 1557 ssize_t vstream_fread_app(VSTREAM *fp, VSTRING *vp, ssize_t len) 1558 { 1559 ssize_t ret; 1560 1561 VSTRING_SPACE(vp, len); 1562 ret = vstream_fread(fp, vstring_end(vp), len); 1563 if (ret > 0) 1564 VSTRING_AT_OFFSET(vp, VSTRING_LEN(vp) + ret); 1565 return (ret); 1566 } 1567 1568 /* vstream_control - fine control */ 1569 1570 void vstream_control(VSTREAM *stream, int name,...) 1571 { 1572 const char *myname = "vstream_control"; 1573 va_list ap; 1574 int floor; 1575 int old_fd; 1576 ssize_t req_bufsize = 0; 1577 VSTREAM *stream2; 1578 int min_data_rate; 1579 1580 #define SWAP(type,a,b) do { type temp = (a); (a) = (b); (b) = (temp); } while (0) 1581 1582 /* 1583 * A crude 'allow' filter for memory streams. 1584 */ 1585 int memory_ops = 1586 ((1 << VSTREAM_CTL_END) | (1 << VSTREAM_CTL_CONTEXT) 1587 | (1 << VSTREAM_CTL_PATH) | (1 << VSTREAM_CTL_EXCEPT) 1588 | (1 << VSTREAM_CTL_OWN_VSTRING)); 1589 1590 for (va_start(ap, name); name != VSTREAM_CTL_END; name = va_arg(ap, int)) { 1591 if ((stream->buf.flags & VSTREAM_FLAG_MEMORY) 1592 && (memory_ops & (1 << name)) == 0) 1593 msg_panic("%s: memory stream does not support VSTREAM_CTL_%d", 1594 VSTREAM_PATH(stream), name); 1595 switch (name) { 1596 case VSTREAM_CTL_READ_FN: 1597 stream->read_fn = va_arg(ap, VSTREAM_RW_FN); 1598 break; 1599 case VSTREAM_CTL_WRITE_FN: 1600 stream->write_fn = va_arg(ap, VSTREAM_RW_FN); 1601 break; 1602 case VSTREAM_CTL_CONTEXT: 1603 stream->context = va_arg(ap, void *); 1604 break; 1605 case VSTREAM_CTL_PATH: 1606 if (stream->path) 1607 myfree(stream->path); 1608 stream->path = mystrdup(va_arg(ap, char *)); 1609 break; 1610 case VSTREAM_CTL_DOUBLE: 1611 if ((stream->buf.flags & VSTREAM_FLAG_DOUBLE) == 0) { 1612 stream->buf.flags |= VSTREAM_FLAG_DOUBLE; 1613 if (stream->buf.flags & VSTREAM_FLAG_READ) { 1614 VSTREAM_SAVE_STATE(stream, read_buf, read_fd); 1615 VSTREAM_FORK_STATE(stream, write_buf, write_fd); 1616 } else { 1617 VSTREAM_SAVE_STATE(stream, write_buf, write_fd); 1618 VSTREAM_FORK_STATE(stream, read_buf, read_fd); 1619 } 1620 } 1621 break; 1622 case VSTREAM_CTL_READ_FD: 1623 if ((stream->buf.flags & VSTREAM_FLAG_DOUBLE) == 0) 1624 msg_panic("VSTREAM_CTL_READ_FD requires double buffering"); 1625 stream->read_fd = va_arg(ap, int); 1626 stream->buf.flags |= VSTREAM_FLAG_NSEEK; 1627 break; 1628 case VSTREAM_CTL_WRITE_FD: 1629 if ((stream->buf.flags & VSTREAM_FLAG_DOUBLE) == 0) 1630 msg_panic("VSTREAM_CTL_WRITE_FD requires double buffering"); 1631 stream->write_fd = va_arg(ap, int); 1632 stream->buf.flags |= VSTREAM_FLAG_NSEEK; 1633 break; 1634 case VSTREAM_CTL_SWAP_FD: 1635 stream2 = va_arg(ap, VSTREAM *); 1636 if ((stream->buf.flags & VSTREAM_FLAG_DOUBLE) 1637 != (stream2->buf.flags & VSTREAM_FLAG_DOUBLE)) 1638 msg_panic("VSTREAM_CTL_SWAP_FD can't swap descriptors between " 1639 "single-buffered and double-buffered streams"); 1640 if (stream->buf.flags & VSTREAM_FLAG_DOUBLE) { 1641 SWAP(int, stream->read_fd, stream2->read_fd); 1642 SWAP(int, stream->write_fd, stream2->write_fd); 1643 stream->fd = ((stream->buf.flags & VSTREAM_FLAG_WRITE) ? 1644 stream->write_fd : stream->read_fd); 1645 } else { 1646 SWAP(int, stream->fd, stream2->fd); 1647 } 1648 break; 1649 case VSTREAM_CTL_TIMEOUT: 1650 if (stream->timeout == 0) 1651 GETTIMEOFDAY(&stream->iotime); 1652 stream->timeout = va_arg(ap, int); 1653 if (stream->timeout < 0) 1654 msg_panic("%s: bad timeout %d", myname, stream->timeout); 1655 break; 1656 case VSTREAM_CTL_EXCEPT: 1657 if (stream->jbuf == 0) 1658 stream->jbuf = 1659 (VSTREAM_JMP_BUF *) mymalloc(sizeof(VSTREAM_JMP_BUF)); 1660 break; 1661 1662 #ifdef VSTREAM_CTL_DUPFD 1663 1664 #define VSTREAM_TRY_DUPFD(backup, fd, floor) do { \ 1665 if (((backup) = (fd)) < floor) { \ 1666 if (((fd) = fcntl((backup), F_DUPFD, (floor))) < 0) \ 1667 msg_fatal("fcntl F_DUPFD %d: %m", (floor)); \ 1668 (void) close(backup); \ 1669 } \ 1670 } while (0) 1671 1672 case VSTREAM_CTL_DUPFD: 1673 floor = va_arg(ap, int); 1674 if (stream->buf.flags & VSTREAM_FLAG_DOUBLE) { 1675 VSTREAM_TRY_DUPFD(old_fd, stream->read_fd, floor); 1676 if (stream->write_fd == old_fd) 1677 stream->write_fd = stream->read_fd; 1678 else 1679 VSTREAM_TRY_DUPFD(old_fd, stream->write_fd, floor); 1680 stream->fd = (stream->buf.flags & VSTREAM_FLAG_READ) ? 1681 stream->read_fd : stream->write_fd; 1682 } else { 1683 VSTREAM_TRY_DUPFD(old_fd, stream->fd, floor); 1684 } 1685 break; 1686 #endif 1687 1688 /* 1689 * Postpone memory (re)allocation until the space is needed. 1690 */ 1691 case VSTREAM_CTL_BUFSIZE: 1692 req_bufsize = va_arg(ap, ssize_t); 1693 /* Heuristic to detect missing (ssize_t) type cast on LP64 hosts. */ 1694 if (req_bufsize < 0 || req_bufsize > INT_MAX) 1695 msg_panic("unreasonable VSTREAM_CTL_BUFSIZE request: %ld", 1696 (long) req_bufsize); 1697 if ((stream->buf.flags & VSTREAM_FLAG_FIXED) == 0 1698 && req_bufsize > stream->req_bufsize) { 1699 if (msg_verbose) 1700 msg_info("fd=%d: stream buffer size old=%ld new=%ld", 1701 vstream_fileno(stream), 1702 (long) stream->req_bufsize, 1703 (long) req_bufsize); 1704 stream->req_bufsize = req_bufsize; 1705 } 1706 break; 1707 1708 /* 1709 * Make no gettimeofday() etc. system call until we really know 1710 * that we need to do I/O. This avoids a performance hit when 1711 * sending or receiving body content one line at a time. 1712 */ 1713 case VSTREAM_CTL_STOP_DEADLINE: 1714 stream->buf.flags &= ~VSTREAM_FLAG_DEADLINE; 1715 break; 1716 case VSTREAM_CTL_START_DEADLINE: 1717 if (stream->timeout <= 0) 1718 msg_panic("%s: bad timeout %d", myname, stream->timeout); 1719 stream->buf.flags |= VSTREAM_FLAG_DEADLINE; 1720 stream->time_limit.tv_sec = stream->timeout; 1721 stream->time_limit.tv_usec = 0; 1722 break; 1723 case VSTREAM_CTL_MIN_DATA_RATE: 1724 min_data_rate = va_arg(ap, int); 1725 if (min_data_rate < 0) 1726 msg_panic("%s: bad min_data_rate %d", myname, min_data_rate); 1727 stream->min_data_rate = min_data_rate; 1728 break; 1729 case VSTREAM_CTL_OWN_VSTRING: 1730 if ((stream->buf.flags |= VSTREAM_FLAG_MEMORY) == 0) 1731 msg_panic("%s: operation on non-VSTRING stream", myname); 1732 stream->buf.flags |= VSTREAM_FLAG_OWN_VSTRING; 1733 break; 1734 default: 1735 msg_panic("%s: bad name %d", myname, name); 1736 } 1737 } 1738 va_end(ap); 1739 } 1740 1741 /* vstream_vprintf - formatted print to stdout */ 1742 1743 VSTREAM *vstream_vprintf(const char *format, va_list ap) 1744 { 1745 VSTREAM *vp = VSTREAM_OUT; 1746 1747 vbuf_print(&vp->buf, format, ap); 1748 return (vp); 1749 } 1750 1751 /* vstream_vfprintf - formatted print engine */ 1752 1753 VSTREAM *vstream_vfprintf(VSTREAM *vp, const char *format, va_list ap) 1754 { 1755 vbuf_print(&vp->buf, format, ap); 1756 return (vp); 1757 } 1758 1759 /* vstream_bufstat - get stream buffer status */ 1760 1761 ssize_t vstream_bufstat(VSTREAM *vp, int command) 1762 { 1763 VBUF *bp; 1764 1765 switch (command & VSTREAM_BST_MASK_DIR) { 1766 case VSTREAM_BST_FLAG_IN: 1767 if (vp->buf.flags & VSTREAM_FLAG_READ) { 1768 bp = &vp->buf; 1769 } else if (vp->buf.flags & VSTREAM_FLAG_DOUBLE) { 1770 bp = &vp->read_buf; 1771 } else { 1772 bp = 0; 1773 } 1774 switch (command & ~VSTREAM_BST_MASK_DIR) { 1775 case VSTREAM_BST_FLAG_PEND: 1776 return (bp ? -bp->cnt : 0); 1777 /* Add other requests below. */ 1778 } 1779 break; 1780 case VSTREAM_BST_FLAG_OUT: 1781 if (vp->buf.flags & VSTREAM_FLAG_WRITE) { 1782 bp = &vp->buf; 1783 } else if (vp->buf.flags & VSTREAM_FLAG_DOUBLE) { 1784 bp = &vp->write_buf; 1785 } else { 1786 bp = 0; 1787 } 1788 switch (command & ~VSTREAM_BST_MASK_DIR) { 1789 case VSTREAM_BST_FLAG_PEND: 1790 return (bp ? bp->len - bp->cnt : 0); 1791 /* Add other requests below. */ 1792 } 1793 break; 1794 } 1795 msg_panic("vstream_bufstat: unknown command: %d", command); 1796 } 1797 1798 #undef vstream_peek /* API binary compatibility. */ 1799 1800 /* vstream_peek - peek at a stream */ 1801 1802 ssize_t vstream_peek(VSTREAM *vp) 1803 { 1804 if (vp->buf.flags & VSTREAM_FLAG_READ) { 1805 return (-vp->buf.cnt); 1806 } else if (vp->buf.flags & VSTREAM_FLAG_DOUBLE) { 1807 return (-vp->read_buf.cnt); 1808 } else { 1809 return (0); 1810 } 1811 } 1812 1813 /* vstream_peek_data - peek at unread data */ 1814 1815 const char *vstream_peek_data(VSTREAM *vp) 1816 { 1817 if (vp->buf.flags & VSTREAM_FLAG_READ) { 1818 return ((const char *) vp->buf.ptr); 1819 } else if (vp->buf.flags & VSTREAM_FLAG_DOUBLE) { 1820 return ((const char *) vp->read_buf.ptr); 1821 } else { 1822 return (0); 1823 } 1824 } 1825 1826 /* vstream_memopen - open a VSTRING */ 1827 1828 VSTREAM *vstream_memreopen(VSTREAM *stream, VSTRING *string, int flags) 1829 { 1830 if (stream == 0) 1831 stream = vstream_subopen(); 1832 else if ((stream->buf.flags & VSTREAM_FLAG_MEMORY) == 0) 1833 msg_panic("vstream_memreopen: cannot reopen non-memory stream"); 1834 stream->fd = -1; 1835 stream->read_fn = 0; 1836 stream->write_fn = 0; 1837 stream->vstring = string; 1838 memcpy(&stream->buf, &stream->vstring->vbuf, sizeof(stream->buf)); 1839 stream->buf.flags |= VSTREAM_FLAG_MEMORY; 1840 switch (VSTREAM_ACC_MASK(flags)) { 1841 case O_RDONLY: 1842 stream->buf.flags |= VSTREAM_FLAG_READ; 1843 /* Prevent reading unwritten data after vstream_fseek(). */ 1844 stream->buf.len = stream->buf.ptr - stream->buf.data; 1845 VSTREAM_BUF_AT_OFFSET(&stream->buf, 0); 1846 break; 1847 case O_WRONLY: 1848 stream->buf.flags |= VSTREAM_FLAG_WRITE; 1849 VSTREAM_BUF_AT_OFFSET(&stream->buf, 0); 1850 break; 1851 case O_APPEND: 1852 stream->buf.flags |= VSTREAM_FLAG_WRITE; 1853 VSTREAM_BUF_AT_OFFSET(&stream->buf, 1854 stream->buf.ptr - stream->buf.data); 1855 break; 1856 default: 1857 msg_panic("vstream_memopen: flags must be one of " 1858 "O_RDONLY, O_WRONLY, or O_APPEND"); 1859 } 1860 return (stream); 1861 } 1862 1863 #ifdef TEST 1864 1865 static void copy_line(ssize_t bufsize) 1866 { 1867 int c; 1868 1869 /* 1870 * Demonstrates that VSTREAM_CTL_BUFSIZE increases the buffer size, but 1871 * does not decrease it. Uses VSTREAM_ERR for non-test output to avoid 1872 * interfering with the test. 1873 */ 1874 vstream_fprintf(VSTREAM_ERR, "buffer size test: copy text with %ld buffer size, ignore requests to shrink\n", 1875 (long) bufsize); 1876 vstream_fflush(VSTREAM_ERR); 1877 vstream_control(VSTREAM_IN, CA_VSTREAM_CTL_BUFSIZE(bufsize), VSTREAM_CTL_END); 1878 vstream_control(VSTREAM_OUT, CA_VSTREAM_CTL_BUFSIZE(bufsize), VSTREAM_CTL_END); 1879 while ((c = VSTREAM_GETC(VSTREAM_IN)) != VSTREAM_EOF) { 1880 VSTREAM_PUTC(c, VSTREAM_OUT); 1881 if (c == '\n') 1882 break; 1883 } 1884 vstream_fflush(VSTREAM_OUT); 1885 vstream_fprintf(VSTREAM_ERR, "actual read/write buffer sizes: %ld/%ld\n\n", 1886 (long) VSTREAM_IN->buf.len, (long) VSTREAM_OUT->buf.len); 1887 vstream_fflush(VSTREAM_ERR); 1888 } 1889 1890 static void printf_number(void) 1891 { 1892 1893 /* 1894 * Demonstrates that vstream_printf() use vbuf_print(). 1895 */ 1896 vstream_printf("formatting test: print a number\n"); 1897 vstream_printf("%d\n\n", 1234567890); 1898 vstream_fflush(VSTREAM_OUT); 1899 } 1900 1901 static void do_memory_stream(void) 1902 { 1903 VSTRING *buf = vstring_alloc(1); 1904 VSTREAM *fp; 1905 off_t offset; 1906 int ch; 1907 1908 /* 1909 * Preload the string. 1910 */ 1911 vstream_printf("memory stream test prep: prefill the VSTRING\n"); 1912 vstring_strcpy(buf, "01234567"); 1913 vstream_printf("VSTRING content length: %ld/%ld, content: %s\n", 1914 (long) VSTRING_LEN(buf), (long) buf->vbuf.len, 1915 vstring_str(buf)); 1916 VSTREAM_PUTCHAR('\n'); 1917 vstream_fflush(VSTREAM_OUT); 1918 1919 /* 1920 * Test: open the memory VSTREAM in write-only mode, and clobber it. 1921 */ 1922 vstream_printf("memory stream test: open the VSTRING for writing, overwrite, close\n"); 1923 fp = vstream_memopen(buf, O_WRONLY); 1924 vstream_printf("initial memory VSTREAM write offset: %ld/%ld\n", 1925 (long) vstream_ftell(fp), (long) fp->buf.len); 1926 vstream_fprintf(fp, "hallo"); 1927 vstream_printf("final memory VSTREAM write offset: %ld/%ld\n", 1928 (long) vstream_ftell(fp), (long) fp->buf.len); 1929 vstream_fclose(fp); 1930 vstream_printf("VSTRING content length: %ld/%ld, content: %s\n", 1931 (long) VSTRING_LEN(buf), (long) buf->vbuf.len, 1932 vstring_str(buf)); 1933 VSTREAM_PUTCHAR('\n'); 1934 vstream_fflush(VSTREAM_OUT); 1935 1936 /* 1937 * Test: open the memory VSTREAM for append. vstream_memopen() sets the 1938 * buffer length to the VSTRING buffer length, and positions the write 1939 * pointer at the VSTRING write position. Write some content, then 1940 * overwrite one character. 1941 */ 1942 vstream_printf("memory stream test: open the VSTRING for append, write multiple, then overwrite 1\n"); 1943 fp = vstream_memopen(buf, O_APPEND); 1944 vstream_printf("initial memory VSTREAM write offset: %ld/%ld\n", 1945 (long) vstream_ftell(fp), (long) fp->buf.len); 1946 vstream_fprintf(fp, " world"); 1947 vstream_printf("final memory VSTREAM write offset: %ld/%ld\n", 1948 (long) vstream_ftell(fp), (long) fp->buf.len); 1949 if (vstream_fflush(fp)) 1950 msg_fatal("vstream_fflush: %m"); 1951 vstream_printf("VSTRING content length: %ld/%ld, content: %s\n", 1952 (long) VSTRING_LEN(buf), (long) buf->vbuf.len, 1953 vstring_str(buf)); 1954 VSTREAM_PUTCHAR('\n'); 1955 1956 /* 1957 * While the stream is still open, replace the second character. 1958 */ 1959 vstream_printf("replace second character and close\n"); 1960 if ((offset = vstream_fseek(fp, 1, SEEK_SET)) != 1) 1961 msg_panic("unexpected vstream_fseek return: %ld, expected: %ld", 1962 (long) offset, (long) 1); 1963 VSTREAM_PUTC('e', fp); 1964 1965 /* 1966 * Skip to the end of the content, so that vstream_fflush() will update 1967 * the VSTRING with the right content length. 1968 */ 1969 if ((offset = vstream_fseek(fp, VSTRING_LEN(buf), SEEK_SET)) != VSTRING_LEN(buf)) 1970 msg_panic("unexpected vstream_fseek return: %ld, expected: %ld", 1971 (long) offset, (long) VSTRING_LEN(buf)); 1972 vstream_fclose(fp); 1973 1974 vstream_printf("VSTRING content length: %ld/%ld, content: %s\n", 1975 (long) VSTRING_LEN(buf), (long) buf->vbuf.len, 1976 vstring_str(buf)); 1977 VSTREAM_PUTCHAR('\n'); 1978 vstream_fflush(VSTREAM_OUT); 1979 1980 /* 1981 * TODO: test that in write/append mode, seek past the end of data will 1982 * result in zero-filled space. 1983 */ 1984 1985 /* 1986 * Test: Open the VSTRING for reading. This time, vstream_memopen() will 1987 * set the VSTREAM buffer length to the content length of the VSTRING, so 1988 * that it won't attempt to read past the end of the content. 1989 */ 1990 vstream_printf("memory stream test: open VSTRING for reading, then read\n"); 1991 fp = vstream_memopen(buf, O_RDONLY); 1992 vstream_printf("initial memory VSTREAM read offset: %ld/%ld\n", 1993 (long) vstream_ftell(fp), (long) fp->buf.len); 1994 vstream_printf("reading memory VSTREAM: "); 1995 while ((ch = VSTREAM_GETC(fp)) != VSTREAM_EOF) 1996 VSTREAM_PUTCHAR(ch); 1997 VSTREAM_PUTCHAR('\n'); 1998 vstream_printf("final memory VSTREAM read offset: %ld/%ld\n", 1999 (long) vstream_ftell(fp), (long) fp->buf.len); 2000 vstream_printf("seeking to offset %ld should work: ", 2001 (long) fp->buf.len + 1); 2002 vstream_fflush(VSTREAM_OUT); 2003 if ((offset = vstream_fseek(fp, fp->buf.len + 1, SEEK_SET)) != fp->buf.len + 1) 2004 msg_panic("unexpected vstream_fseek return: %ld, expected: %ld", 2005 (long) offset, (long) fp->buf.len + 1); 2006 vstream_printf("PASS\n"); 2007 vstream_fflush(VSTREAM_OUT); 2008 vstream_printf("VSTREAM_GETC should return VSTREAM_EOF\n"); 2009 ch = VSTREAM_GETC(fp); 2010 if (ch != VSTREAM_EOF) 2011 msg_panic("unexpected vstream_fseek VSTREAM_GETC return: %d, expected: %d", 2012 ch, VSTREAM_EOF); 2013 vstream_printf("PASS\n"); 2014 vstream_printf("final memory VSTREAM read offset: %ld/%ld\n", 2015 (long) vstream_ftell(fp), (long) fp->buf.len); 2016 vstream_printf("VSTRING content length: %ld/%ld, content: %s\n", 2017 (long) VSTRING_LEN(buf), (long) buf->vbuf.len, 2018 vstring_str(buf)); 2019 VSTREAM_PUTCHAR('\n'); 2020 vstream_fflush(VSTREAM_OUT); 2021 vstream_fclose(fp); 2022 vstring_free(buf); 2023 } 2024 2025 /* 2026 * Exercise some of the features. 2027 */ 2028 2029 #include <msg_vstream.h> 2030 2031 int main(int argc, char **argv) 2032 { 2033 msg_vstream_init(argv[0], VSTREAM_ERR); 2034 2035 /* 2036 * Test buffer expansion and shrinking. Formatted print may silently 2037 * expand the write buffer and cause multiple bytes to be written. 2038 */ 2039 copy_line(1); /* one-byte read/write */ 2040 copy_line(2); /* two-byte read/write */ 2041 copy_line(1); /* two-byte read/write */ 2042 printf_number(); /* multi-byte write */ 2043 do_memory_stream(); 2044 2045 exit(0); 2046 } 2047 2048 #endif 2049