1/*++ 2/* NAME 3/* timed_write 3 4/* SUMMARY 5/* write operation with pre-write timeout 6/* SYNOPSIS 7/* #include <iostuff.h> 8/* 9/* ssize_t timed_write(fd, buf, len, timeout, context) 10/* int fd; 11/* const void *buf; 12/* size_t len; 13/* int timeout; 14/* void *context; 15/* DESCRIPTION 16/* timed_write() performs a write() operation when the specified 17/* descriptor becomes writable within a user-specified deadline. 18/* 19/* Arguments: 20/* .IP fd 21/* File descriptor in the range 0..FD_SETSIZE. 22/* .IP buf 23/* Write buffer pointer. 24/* .IP len 25/* Write buffer size. 26/* .IP timeout 27/* The deadline in seconds. If this is <= 0, the deadline feature 28/* is disabled. 29/* .IP context 30/* Application context. This parameter is unused. It exists only 31/* for the sake of VSTREAM compatibility. 32/* DIAGNOSTICS 33/* When the operation does not complete within the deadline, the 34/* result value is -1, and errno is set to ETIMEDOUT. 35/* All other returns are identical to those of a write(2) operation. 36/* LICENSE 37/* .ad 38/* .fi 39/* The Secure Mailer license must be distributed with this software. 40/* AUTHOR(S) 41/* Wietse Venema 42/* IBM T.J. Watson Research 43/* P.O. Box 704 44/* Yorktown Heights, NY 10598, USA 45/*--*/ 46 47/* System library. */ 48 49#include <sys_defs.h> 50#include <unistd.h> 51#include <errno.h> 52 53/* Utility library. */ 54 55#include <msg.h> 56#include <iostuff.h> 57 58/* timed_write - write with deadline */ 59 60ssize_t timed_write(int fd, void *buf, size_t len, 61 int timeout, void *unused_context) 62{ 63 ssize_t ret; 64 65 /* 66 * Wait for a limited amount of time for something to happen. If nothing 67 * happens, report an ETIMEDOUT error. 68 * 69 * XXX Solaris 8 read() fails with EAGAIN after read-select() returns 70 * success. The code below exists just in case their write implementation 71 * is equally broken. 72 * 73 * This condition may also be found on systems where select() returns 74 * success on pipes with less than PIPE_BUF bytes of space, and with 75 * badly designed software where multiple writers are fighting for access 76 * to the same resource. 77 */ 78 for (;;) { 79 if (timeout > 0 && write_wait(fd, timeout) < 0) 80 return (-1); 81 if ((ret = write(fd, buf, len)) < 0 && timeout > 0 && errno == EAGAIN) { 82 msg_warn("write() returns EAGAIN on a writable file descriptor!"); 83 msg_warn("pausing to avoid going into a tight select/write loop!"); 84 sleep(1); 85 continue; 86 } else if (ret < 0 && errno == EINTR) { 87 continue; 88 } else { 89 return (ret); 90 } 91 } 92} 93