4 * poll(2) emulation for Windows
6 * This emulates just-enough poll functionality on Windows to work in the
7 * context of the openssl(1) program. This is not a replacement for
8 * POSIX.1-2001 poll(2), though it may come closer than I care to admit.
10 * Dongsheng Song <dongsheng.song@gmail.com>
11 * Brent Cook <bcook@openbsd.org>
21 conn_is_closed(int fd)
24 int ret = recv(fd, buf, 1, MSG_PEEK);
26 switch (WSAGetLastError()) {
38 conn_has_oob_data(int fd)
41 return (recv(fd, buf, 1, MSG_PEEK | MSG_OOB) == 1);
49 WSANETWORKEVENTS events;
50 return (WSAEnumNetworkEvents((SOCKET)fd, NULL, &events) == 0);
54 compute_select_revents(int fd, short events,
55 fd_set *rfds, fd_set *wfds, fd_set *efds)
59 if ((events & (POLLIN | POLLRDNORM | POLLRDBAND)) &&
61 if (conn_is_closed(fd))
64 rc |= POLLIN | POLLRDNORM;
67 if ((events & (POLLOUT | POLLWRNORM | POLLWRBAND)) &&
71 if (FD_ISSET(fd, efds)) {
72 if (conn_is_closed(fd))
74 else if (conn_has_oob_data(fd))
75 rc |= POLLRDBAND | POLLPRI;
82 compute_wait_revents(HANDLE h, short events, int object, int wait_rc)
89 * Assume we can always write to file handles (probably a bad
90 * assumption but works for now, at least it doesn't block).
92 if (events & (POLLOUT | POLLWRNORM))
96 * Check if this handle was signaled by WaitForMultipleObjects
98 if (wait_rc >= WAIT_OBJECT_0 && (object == (wait_rc - WAIT_OBJECT_0))
99 && (events & (POLLIN | POLLRDNORM))) {
102 * Check if this file is stdin, and if so, if it is a console.
104 if (h == GetStdHandle(STD_INPUT_HANDLE) &&
105 PeekConsoleInput(h, &record, 1, &num_read) == 1) {
108 * Handle the input console buffer differently,
109 * since it can signal on other events like
110 * window and mouse, but read can still block.
112 if (record.EventType == KEY_EVENT &&
113 record.Event.KeyEvent.bKeyDown) {
117 * Flush non-character events from the
120 ReadConsoleInput(h, &record, 1, &num_read);
131 wsa_select_errno(int err)
140 * Windows uses WSAEFAULT for both resource allocation failures
141 * and arguments not being contained in the user's address
142 * space. So, we have to choose EFAULT or ENOMEM.
149 case WSANOTINITIALISED:
160 poll(struct pollfd *pfds, nfds_t nfds, int timeout_ms)
163 int timespent_ms, looptime_ms;
168 fd_set rfds, wfds, efds;
176 HANDLE handles[FD_SETSIZE];
194 for (i = 0; i < nfds; i++) {
195 if ((int)pfds[i].fd < 0)
198 if (is_socket(pfds[i].fd)) {
199 if (num_sockets >= FD_SETSIZE) {
204 FD_SET(pfds[i].fd, &efds);
207 (POLLIN | POLLRDNORM | POLLRDBAND)) {
208 FD_SET(pfds[i].fd, &rfds);
212 (POLLOUT | POLLWRNORM | POLLWRBAND)) {
213 FD_SET(pfds[i].fd, &wfds);
218 if (num_handles >= FD_SETSIZE) {
223 handles[num_handles++] =
224 (HANDLE)_get_osfhandle(pfds[i].fd);
229 * Determine if the files, pipes, sockets, consoles, etc. have signaled.
231 * Do this by alternating a loop between WaitForMultipleObjects for
232 * non-sockets and and select for sockets.
234 * I tried to implement this all in terms of WaitForMultipleObjects
235 * with a select-based 'poll' of the sockets at the end to get extra
236 * specific socket status.
238 * However, the cost of setting up an event handle for each socket and
239 * cleaning them up reliably was pretty high. Since the event handle
240 * associated with a socket is also global, creating a new one here
241 * cancels one that may exist externally to this function.
243 * At any rate, even if global socket event handles were not an issue,
244 * the 'FD_WRITE' status of a socket event handle does not behave in an
245 * expected fashion, being triggered by an edge on a write buffer rather
246 * than simply triggering if there is space available.
249 wait_rc = WAIT_FAILED;
252 timeout_ms = INFINITE;
253 looptime_ms = timeout_ms > 100 ? 100 : timeout_ms;
256 struct timeval tv = {0, looptime_ms * 1000};
257 int handle_signaled = 0;
260 * Check if any file handles have signaled
263 wait_rc = WaitForMultipleObjects(num_handles, handles,
265 if (wait_rc == WAIT_FAILED) {
267 * The documentation for WaitForMultipleObjects
268 * does not specify what values GetLastError
269 * may return here. Rather than enumerate
270 * badness like for wsa_select_errno, assume a
271 * general errno value.
279 * If we signaled on a file handle, don't wait on the sockets.
281 if (wait_rc >= WAIT_OBJECT_0 &&
282 (wait_rc <= WAIT_OBJECT_0 + num_handles - 1)) {
288 * Check if any sockets have signaled
290 rc = select(0, &rfds, &wfds, &efds, &tv);
291 if (!handle_signaled && rc == SOCKET_ERROR)
292 return wsa_select_errno(WSAGetLastError());
294 if (handle_signaled || (num_sockets && rc > 0))
297 timespent_ms += looptime_ms;
299 } while (timespent_ms < timeout_ms);
303 for (i = 0; i < nfds; i++) {
306 if ((int)pfds[i].fd < 0)
309 if (is_socket(pfds[i].fd)) {
311 pfds[i].revents = compute_select_revents(pfds[i].fd,
312 pfds[i].events, &rfds, &wfds, &efds);
315 pfds[i].revents = compute_wait_revents(
316 handles[num_handles], pfds[i].events, num_handles,