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
109 int     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 
poll_fd_bsd(int fd,int request,int time_limit,int true_res,int false_res)148 int     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 
poll_fd_sysv(int fd,int request,int time_limit,int true_res,int false_res)229 int     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