1 /*++
2 /* NAME
3 /*	timed_read 3
4 /* SUMMARY
5 /*	read operation with pre-read timeout
6 /* SYNOPSIS
7 /*	#include <iostuff.h>
8 /*
9 /*	ssize_t	timed_read(fd, buf, len, timeout, context)
10 /*	int	fd;
11 /*	void	*buf;
12 /*	size_t	len;
13 /*	int	timeout;
14 /*	void	*context;
15 /* DESCRIPTION
16 /*	timed_read() performs a read() operation when the specified
17 /*	descriptor becomes readable within a user-specified deadline.
18 /*
19 /*	Arguments:
20 /* .IP fd
21 /*	File descriptor in the range 0..FD_SETSIZE.
22 /* .IP buf
23 /*	Read buffer pointer.
24 /* .IP len
25 /*	Read 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 read(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_read - read with deadline */
59 
timed_read(int fd,void * buf,size_t len,int timeout,void * unused_context)60 ssize_t timed_read(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.
71      */
72     for (;;) {
73 	if (timeout > 0 && read_wait(fd, timeout) < 0)
74 	    return (-1);
75 	if ((ret = read(fd, buf, len)) < 0 && timeout > 0 && errno == EAGAIN) {
76 	    msg_warn("read() returns EAGAIN on a readable file descriptor!");
77 	    msg_warn("pausing to avoid going into a tight select/read loop!");
78 	    sleep(1);
79 	    continue;
80 	} else if (ret < 0 && errno == EINTR) {
81 	    continue;
82 	} else {
83 	    return (ret);
84 	}
85     }
86 }
87