1 /*	$NetBSD: timed_write.c,v 1.1.1.1 2009/06/23 10:09:01 tron Exp $	*/
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 
62 ssize_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