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