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