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