1/*++
2/* NAME
3/*	poll_fd 3
4/* SUMMARY
5/*	wait until file descriptor becomes readable or writable
6/* SYNOPSIS
7/*	#include <iostuff.h>
8/*
9/*	int	readable(fd)
10/*	int	fd;
11/*
12/*	int	writable(fd)
13/*	int	fd;
14/*
15/*	int	read_wait(fd, time_limit)
16/*	int	fd;
17/*	int	time_limit;
18/*
19/*	int	write_wait(fd, time_limit)
20/*	int	fd;
21/*	int	time_limit;
22/*
23/*	int	poll_fd(fd, request, time_limit, true_res, false_res)
24/*	int	fd;
25/*	int	request;
26/*	int	time_limit;
27/*	int	true_res;
28/*	int	false_res;
29/* DESCRIPTION
30/*	The read*() and write*() functions in this module are macros
31/*	that provide a convenient interface to poll_fd().
32/*
33/*	readable() asks the kernel if the specified file descriptor
34/*	is readable, i.e. a read operation would not block.
35/*
36/*	writable() asks the kernel if the specified file descriptor
37/*	is writable, i.e. a write operation would not block.
38/*
39/*	read_wait() waits until the specified file descriptor becomes
40/*	readable, or until the time limit is reached.
41/*
42/*	write_wait() waits until the specified file descriptor
43/*	becomes writable, or until the time limit is reached.
44/*
45/*	poll_fd() waits until the specified file descriptor becomes
46/*	readable or writable, or until the time limit is reached.
47/*
48/*	Arguments:
49/* .IP fd
50/*	File descriptor. With implementations based on select(), a
51/*	best effort is made to handle descriptors >=FD_SETSIZE.
52/* .IP request
53/*	POLL_FD_READ (wait until readable) or POLL_FD_WRITE (wait
54/*	until writable).
55/* .IP time_limit
56/*	A positive value specifies a time limit in seconds. A zero
57/*	value effects a poll (return immediately).  A negative value
58/*	means wait until the requested POLL_FD_READ or POLL_FD_WRITE
59/*	condition becomes true.
60/* .IP true_res
61/*	Result value when the requested POLL_FD_READ or POLL_FD_WRITE
62/*	condition is true.
63/* .IP false_res
64/*	Result value when the requested POLL_FD_READ or POLL_FD_WRITE
65/*	condition is false.
66/* DIAGNOSTICS
67/*	Panic: interface violation. All system call errors are fatal
68/*	unless specified otherwise.
69/*
70/*	readable() and writable() return 1 when the requested
71/*	POLL_FD_READ or POLL_FD_WRITE condition is true, zero when
72/*	it is false. They never return an error indication.
73/*
74/*	read_wait() and write_wait() return zero when the requested
75/*	POLL_FD_READ or POLL_FD_WRITE condition is true, -1 (with
76/*	errno set to ETIMEDOUT) when it is false.
77/*
78/*	poll_fd() returns true_res when the requested POLL_FD_READ
79/*	or POLL_FD_WRITE condition is true, false_res when it is
80/*	false.  When poll_fd() returns a false_res value < 0, it
81/*	also sets errno to ETIMEDOUT.
82/* LICENSE
83/* .ad
84/* .fi
85/*	The Secure Mailer license must be distributed with this software.
86/* AUTHOR(S)
87/*	Wietse Venema
88/*	IBM T.J. Watson Research
89/*	P.O. Box 704
90/*	Yorktown Heights, NY 10598, USA
91/*--*/
92
93/* System library. */
94
95#include <sys_defs.h>
96#include <sys/time.h>
97#include <signal.h>
98#include <errno.h>
99#include <unistd.h>
100#include <string.h>
101
102 /*
103  * Use poll() with fall-back to select(). MacOSX needs this for devices.
104  */
105#if defined(USE_SYSV_POLL_THEN_SELECT)
106#define poll_fd_sysv	poll_fd
107#define USE_SYSV_POLL
108#define USE_BSD_SELECT
109int     poll_fd_bsd(int, int, int, int, int);
110
111 /*
112  * Use select() only.
113  */
114#elif defined(USE_BSD_SELECT)
115#define poll_fd_bsd	poll_fd
116#undef USE_SYSV_POLL
117
118 /*
119  * Use poll() only.
120  */
121#elif defined(USE_SYSV_POLL)
122#define poll_fd_sysv	poll_fd
123
124 /*
125  * Sanity check.
126  */
127#else
128#error "specify USE_SYSV_POLL, USE_BSD_SELECT or USE_SYSV_POLL_THEN_SELECT"
129#endif
130
131#ifdef USE_SYSV_POLL
132#include <poll.h>
133#endif
134
135#ifdef USE_SYS_SELECT_H
136#include <sys/select.h>
137#endif
138
139/* Utility library. */
140
141#include <msg.h>
142#include <iostuff.h>
143
144#ifdef USE_BSD_SELECT
145
146/* poll_fd_bsd - block with time_limit until file descriptor is ready */
147
148int     poll_fd_bsd(int fd, int request, int time_limit,
149		            int true_res, int false_res)
150{
151    fd_set  req_fds;
152    fd_set *read_fds;
153    fd_set *write_fds;
154    fd_set  except_fds;
155    struct timeval tv;
156    struct timeval *tp;
157    int     temp_fd = -1;
158
159    /*
160     * Sanity checks.
161     */
162    if (FD_SETSIZE <= fd) {
163	if ((temp_fd = dup(fd)) < 0 || temp_fd >= FD_SETSIZE)
164	    msg_fatal("descriptor %d does not fit FD_SETSIZE %d", fd, FD_SETSIZE);
165	fd = temp_fd;
166    }
167
168    /*
169     * Use select() so we do not depend on alarm() and on signal() handlers.
170     * Restart select() when interrupted by some signal. Some select()
171     * implementations reduce the time to wait when interrupted, which is
172     * exactly what we want.
173     */
174    FD_ZERO(&req_fds);
175    FD_SET(fd, &req_fds);
176    except_fds = req_fds;
177    if (request == POLL_FD_READ) {
178	read_fds = &req_fds;
179	write_fds = 0;
180    } else if (request == POLL_FD_WRITE) {
181	read_fds = 0;
182	write_fds = &req_fds;
183    } else {
184	msg_panic("poll_fd: bad request %d", request);
185    }
186
187    if (time_limit >= 0) {
188	tv.tv_usec = 0;
189	tv.tv_sec = time_limit;
190	tp = &tv;
191    } else {
192	tp = 0;
193    }
194
195    for (;;) {
196	switch (select(fd + 1, read_fds, write_fds, &except_fds, tp)) {
197	case -1:
198	    if (errno != EINTR)
199		msg_fatal("select: %m");
200	    continue;
201	case 0:
202	    if (temp_fd != -1)
203		(void) close(temp_fd);
204	    if (false_res < 0)
205		errno = ETIMEDOUT;
206	    return (false_res);
207	default:
208	    if (temp_fd != -1)
209		(void) close(temp_fd);
210	    return (true_res);
211	}
212    }
213}
214
215#endif
216
217#ifdef USE_SYSV_POLL
218
219#ifdef USE_SYSV_POLL_THEN_SELECT
220#define HANDLE_SYSV_POLL_ERROR(fd, req, time_limit, true_res, false_res) \
221	return (poll_fd_bsd((fd), (req), (time_limit), (true_res), (false_res)))
222#else
223#define HANDLE_SYSV_POLL_ERROR(fd, req, time_limit, true_res, false_res) \
224	msg_fatal("poll: %m")
225#endif
226
227/* poll_fd_sysv - block with time_limit until file descriptor is ready */
228
229int     poll_fd_sysv(int fd, int request, int time_limit,
230		             int true_res, int false_res)
231{
232    struct pollfd pollfd;
233
234    /*
235     * System-V poll() is optimal for polling a few descriptors.
236     */
237#define WAIT_FOR_EVENT	(-1)
238
239    pollfd.fd = fd;
240    if (request == POLL_FD_READ) {
241	pollfd.events = POLLIN;
242    } else if (request == POLL_FD_WRITE) {
243	pollfd.events = POLLOUT;
244    } else {
245	msg_panic("poll_fd: bad request %d", request);
246    }
247
248    for (;;) {
249	switch (poll(&pollfd, 1, time_limit < 0 ?
250		     WAIT_FOR_EVENT : time_limit * 1000)) {
251	case -1:
252	    if (errno != EINTR)
253		HANDLE_SYSV_POLL_ERROR(fd, request, time_limit,
254				       true_res, false_res);
255	    continue;
256	case 0:
257	    if (false_res < 0)
258		errno = ETIMEDOUT;
259	    return (false_res);
260	default:
261	    if (pollfd.revents & POLLNVAL)
262		HANDLE_SYSV_POLL_ERROR(fd, request, time_limit,
263				       true_res, false_res);
264	    return (true_res);
265	}
266    }
267}
268
269#endif
270