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
60ssize_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