1 /* Emulation for poll(2)
2 Contributed by Paolo Bonzini.
3
4 Copyright 2001-2003, 2006-2021 Free Software Foundation, Inc.
5
6 This file is part of gnulib.
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
11 any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License along
19 with this program; if not, see <https://www.gnu.org/licenses/>. */
20
21 /* Tell gcc not to warn about the (nfd < 0) tests, below. */
22 #if (__GNUC__ == 4 && 3 <= __GNUC_MINOR__) || 4 < __GNUC__
23 # pragma GCC diagnostic ignored "-Wtype-limits"
24 #endif
25
26 #include <config.h>
27 #include <alloca.h>
28
29 #include <sys/types.h>
30
31 /* Specification. */
32 #include <poll.h>
33
34 #include <errno.h>
35 #include <limits.h>
36
37 #if defined _WIN32 && ! defined __CYGWIN__
38 # define WINDOWS_NATIVE
39 # include <winsock2.h>
40 # include <windows.h>
41 # include <io.h>
42 # include <stdio.h>
43 # include <conio.h>
44 # if GNULIB_MSVC_NOTHROW
45 # include "msvc-nothrow.h"
46 # else
47 # include <io.h>
48 # endif
49 #else
50 # include <sys/time.h>
51 # include <unistd.h>
52 #endif
53
54 #include <sys/select.h>
55 #include <sys/socket.h>
56
57 #ifdef HAVE_SYS_IOCTL_H
58 # include <sys/ioctl.h>
59 #endif
60 #ifdef HAVE_SYS_FILIO_H
61 # include <sys/filio.h>
62 #endif
63
64 #include <time.h>
65
66 #include "assure.h"
67
68 #ifndef INFTIM
69 # define INFTIM (-1)
70 #endif
71
72 /* BeOS does not have MSG_PEEK. */
73 #ifndef MSG_PEEK
74 # define MSG_PEEK 0
75 #endif
76
77 #ifdef WINDOWS_NATIVE
78
79 /* Don't assume that UNICODE is not defined. */
80 # undef GetModuleHandle
81 # define GetModuleHandle GetModuleHandleA
82 # undef PeekConsoleInput
83 # define PeekConsoleInput PeekConsoleInputA
84 # undef CreateEvent
85 # define CreateEvent CreateEventA
86 # undef PeekMessage
87 # define PeekMessage PeekMessageA
88 # undef DispatchMessage
89 # define DispatchMessage DispatchMessageA
90
91 /* Do *not* use the function WSAPoll
92 <https://docs.microsoft.com/en-us/windows/desktop/api/winsock2/nf-winsock2-wsapoll>
93 because there is a bug named “Windows 8 Bugs 309411 - WSAPoll does not
94 report failed connections” that Microsoft won't fix.
95 See Daniel Stenberg: "WASPoll is broken"
96 <https://daniel.haxx.se/blog/2012/10/10/wsapoll-is-broken/>. */
97
98 /* Here we need the recv() function from Windows, that takes a SOCKET as
99 first argument, not any possible gnulib override. */
100 # undef recv
101
102 /* Here we need the select() function from Windows, because we pass bit masks
103 of SOCKETs, not bit masks of FDs. */
104 # undef select
105
106 /* Here we need timeval from Windows since this is what the select() function
107 from Windows requires. */
108 # undef timeval
109
110 /* Avoid warnings from gcc -Wcast-function-type. */
111 # define GetProcAddress \
112 (void *) GetProcAddress
113
IsConsoleHandle(HANDLE h)114 static BOOL IsConsoleHandle (HANDLE h)
115 {
116 DWORD mode;
117 return GetConsoleMode (h, &mode) != 0;
118 }
119
120 static BOOL
IsSocketHandle(HANDLE h)121 IsSocketHandle (HANDLE h)
122 {
123 WSANETWORKEVENTS ev;
124
125 if (IsConsoleHandle (h))
126 return FALSE;
127
128 /* Under Wine, it seems that getsockopt returns 0 for pipes too.
129 WSAEnumNetworkEvents instead distinguishes the two correctly. */
130 ev.lNetworkEvents = 0xDEADBEEF;
131 WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
132 return ev.lNetworkEvents != 0xDEADBEEF;
133 }
134
135 /* Declare data structures for ntdll functions. */
136 typedef struct _FILE_PIPE_LOCAL_INFORMATION {
137 ULONG NamedPipeType;
138 ULONG NamedPipeConfiguration;
139 ULONG MaximumInstances;
140 ULONG CurrentInstances;
141 ULONG InboundQuota;
142 ULONG ReadDataAvailable;
143 ULONG OutboundQuota;
144 ULONG WriteQuotaAvailable;
145 ULONG NamedPipeState;
146 ULONG NamedPipeEnd;
147 } FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION;
148
149 typedef struct _IO_STATUS_BLOCK
150 {
151 union {
152 DWORD Status;
153 PVOID Pointer;
154 } u;
155 ULONG_PTR Information;
156 } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
157
158 typedef enum _FILE_INFORMATION_CLASS {
159 FilePipeLocalInformation = 24
160 } FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
161
162 typedef DWORD (WINAPI *PNtQueryInformationFile)
163 (HANDLE, IO_STATUS_BLOCK *, VOID *, ULONG, FILE_INFORMATION_CLASS);
164
165 # ifndef PIPE_BUF
166 # define PIPE_BUF 512
167 # endif
168
169 /* Compute revents values for file handle H. If some events cannot happen
170 for the handle, eliminate them from *P_SOUGHT. */
171
172 static int
windows_compute_revents(HANDLE h,int * p_sought)173 windows_compute_revents (HANDLE h, int *p_sought)
174 {
175 int i, ret, happened;
176 INPUT_RECORD *irbuffer;
177 DWORD avail, nbuffer;
178 BOOL bRet;
179 IO_STATUS_BLOCK iosb;
180 FILE_PIPE_LOCAL_INFORMATION fpli;
181 static PNtQueryInformationFile NtQueryInformationFile;
182 static BOOL once_only;
183
184 switch (GetFileType (h))
185 {
186 case FILE_TYPE_PIPE:
187 if (!once_only)
188 {
189 NtQueryInformationFile = (PNtQueryInformationFile)
190 GetProcAddress (GetModuleHandle ("ntdll.dll"),
191 "NtQueryInformationFile");
192 once_only = TRUE;
193 }
194
195 happened = 0;
196 if (PeekNamedPipe (h, NULL, 0, NULL, &avail, NULL) != 0)
197 {
198 if (avail)
199 happened |= *p_sought & (POLLIN | POLLRDNORM);
200 }
201 else if (GetLastError () == ERROR_BROKEN_PIPE)
202 happened |= POLLHUP;
203
204 else
205 {
206 /* It was the write-end of the pipe. Check if it is writable.
207 If NtQueryInformationFile fails, optimistically assume the pipe is
208 writable. This could happen on Windows 9x, where
209 NtQueryInformationFile is not available, or if we inherit a pipe
210 that doesn't permit FILE_READ_ATTRIBUTES access on the write end
211 (I think this should not happen since Windows XP SP2; WINE seems
212 fine too). Otherwise, ensure that enough space is available for
213 atomic writes. */
214 memset (&iosb, 0, sizeof (iosb));
215 memset (&fpli, 0, sizeof (fpli));
216
217 if (!NtQueryInformationFile
218 || NtQueryInformationFile (h, &iosb, &fpli, sizeof (fpli),
219 FilePipeLocalInformation)
220 || fpli.WriteQuotaAvailable >= PIPE_BUF
221 || (fpli.OutboundQuota < PIPE_BUF &&
222 fpli.WriteQuotaAvailable == fpli.OutboundQuota))
223 happened |= *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
224 }
225 return happened;
226
227 case FILE_TYPE_CHAR:
228 ret = WaitForSingleObject (h, 0);
229 if (!IsConsoleHandle (h))
230 return ret == WAIT_OBJECT_0 ? *p_sought & ~(POLLPRI | POLLRDBAND) : 0;
231
232 nbuffer = avail = 0;
233 bRet = GetNumberOfConsoleInputEvents (h, &nbuffer);
234 if (bRet)
235 {
236 /* Input buffer. */
237 *p_sought &= POLLIN | POLLRDNORM;
238 if (nbuffer == 0)
239 return POLLHUP;
240 if (!*p_sought)
241 return 0;
242
243 irbuffer = (INPUT_RECORD *) alloca (nbuffer * sizeof (INPUT_RECORD));
244 bRet = PeekConsoleInput (h, irbuffer, nbuffer, &avail);
245 if (!bRet || avail == 0)
246 return POLLHUP;
247
248 for (i = 0; i < avail; i++)
249 if (irbuffer[i].EventType == KEY_EVENT)
250 return *p_sought;
251 return 0;
252 }
253 else
254 {
255 /* Screen buffer. */
256 *p_sought &= POLLOUT | POLLWRNORM | POLLWRBAND;
257 return *p_sought;
258 }
259
260 default:
261 ret = WaitForSingleObject (h, 0);
262 if (ret == WAIT_OBJECT_0)
263 return *p_sought & ~(POLLPRI | POLLRDBAND);
264
265 return *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
266 }
267 }
268
269 /* Convert fd_sets returned by select into revents values. */
270
271 static int
windows_compute_revents_socket(SOCKET h,int sought,long lNetworkEvents)272 windows_compute_revents_socket (SOCKET h, int sought, long lNetworkEvents)
273 {
274 int happened = 0;
275
276 if ((lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE)) == FD_ACCEPT)
277 happened |= (POLLIN | POLLRDNORM) & sought;
278
279 else if (lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE))
280 {
281 int r, error;
282
283 char data[64];
284 WSASetLastError (0);
285 r = recv (h, data, sizeof (data), MSG_PEEK);
286 error = WSAGetLastError ();
287 WSASetLastError (0);
288
289 if (r > 0 || error == WSAENOTCONN)
290 happened |= (POLLIN | POLLRDNORM) & sought;
291
292 /* Distinguish hung-up sockets from other errors. */
293 else if (r == 0 || error == WSAESHUTDOWN || error == WSAECONNRESET
294 || error == WSAECONNABORTED || error == WSAENETRESET)
295 happened |= POLLHUP;
296
297 else
298 happened |= POLLERR;
299 }
300
301 if (lNetworkEvents & (FD_WRITE | FD_CONNECT))
302 happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;
303
304 if (lNetworkEvents & FD_OOB)
305 happened |= (POLLPRI | POLLRDBAND) & sought;
306
307 return happened;
308 }
309
310 #else /* !MinGW */
311
312 /* Convert select(2) returned fd_sets into poll(2) revents values. */
313 static int
compute_revents(int fd,int sought,fd_set * rfds,fd_set * wfds,fd_set * efds)314 compute_revents (int fd, int sought, fd_set *rfds, fd_set *wfds, fd_set *efds)
315 {
316 int happened = 0;
317 if (FD_ISSET (fd, rfds))
318 {
319 int r;
320 int socket_errno;
321
322 # if defined __MACH__ && defined __APPLE__
323 /* There is a bug in Mac OS X that causes it to ignore MSG_PEEK
324 for some kinds of descriptors. Detect if this descriptor is a
325 connected socket, a server socket, or something else using a
326 0-byte recv, and use ioctl(2) to detect POLLHUP. */
327 r = recv (fd, NULL, 0, MSG_PEEK);
328 socket_errno = (r < 0) ? errno : 0;
329 if (r == 0 || socket_errno == ENOTSOCK)
330 ioctl (fd, FIONREAD, &r);
331 # else
332 char data[64];
333 r = recv (fd, data, sizeof (data), MSG_PEEK);
334 socket_errno = (r < 0) ? errno : 0;
335 # endif
336 if (r == 0)
337 happened |= POLLHUP;
338
339 /* If the event happened on an unconnected server socket,
340 that's fine. */
341 else if (r > 0 || ( /* (r == -1) && */ socket_errno == ENOTCONN))
342 happened |= (POLLIN | POLLRDNORM) & sought;
343
344 /* Distinguish hung-up sockets from other errors. */
345 else if (socket_errno == ESHUTDOWN || socket_errno == ECONNRESET
346 || socket_errno == ECONNABORTED || socket_errno == ENETRESET)
347 happened |= POLLHUP;
348
349 /* some systems can't use recv() on non-socket, including HP NonStop */
350 else if (socket_errno == ENOTSOCK)
351 happened |= (POLLIN | POLLRDNORM) & sought;
352
353 else
354 happened |= POLLERR;
355 }
356
357 if (FD_ISSET (fd, wfds))
358 happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;
359
360 if (FD_ISSET (fd, efds))
361 happened |= (POLLPRI | POLLRDBAND) & sought;
362
363 return happened;
364 }
365 #endif /* !MinGW */
366
367 int
poll(struct pollfd * pfd,nfds_t nfd,int timeout)368 poll (struct pollfd *pfd, nfds_t nfd, int timeout)
369 {
370 #ifndef WINDOWS_NATIVE
371 fd_set rfds, wfds, efds;
372 struct timeval tv;
373 struct timeval *ptv;
374 int maxfd, rc;
375 nfds_t i;
376
377 if (nfd > INT_MAX)
378 {
379 errno = EINVAL;
380 return -1;
381 }
382 /* Don't check directly for NFD greater than OPEN_MAX. Any practical use
383 of a too-large NFD is caught by one of the other checks below, and
384 checking directly for getdtablesize is too much of a portability
385 and/or performance and/or correctness hassle. */
386
387 /* EFAULT is not necessary to implement, but let's do it in the
388 simplest case. */
389 if (!pfd && nfd)
390 {
391 errno = EFAULT;
392 return -1;
393 }
394
395 /* convert timeout number into a timeval structure */
396 if (timeout == 0)
397 {
398 ptv = &tv;
399 ptv->tv_sec = 0;
400 ptv->tv_usec = 0;
401 }
402 else if (timeout > 0)
403 {
404 ptv = &tv;
405 ptv->tv_sec = timeout / 1000;
406 ptv->tv_usec = (timeout % 1000) * 1000;
407 }
408 else if (timeout == INFTIM)
409 /* wait forever */
410 ptv = NULL;
411 else
412 {
413 errno = EINVAL;
414 return -1;
415 }
416
417 /* create fd sets and determine max fd */
418 maxfd = -1;
419 FD_ZERO (&rfds);
420 FD_ZERO (&wfds);
421 FD_ZERO (&efds);
422 for (i = 0; i < nfd; i++)
423 {
424 if (pfd[i].fd < 0)
425 continue;
426 if (maxfd < pfd[i].fd)
427 {
428 maxfd = pfd[i].fd;
429 if (FD_SETSIZE <= maxfd)
430 {
431 errno = EINVAL;
432 return -1;
433 }
434 }
435 if (pfd[i].events & (POLLIN | POLLRDNORM))
436 FD_SET (pfd[i].fd, &rfds);
437 /* see select(2): "the only exceptional condition detectable
438 is out-of-band data received on a socket", hence we push
439 POLLWRBAND events onto wfds instead of efds. */
440 if (pfd[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND))
441 FD_SET (pfd[i].fd, &wfds);
442 if (pfd[i].events & (POLLPRI | POLLRDBAND))
443 FD_SET (pfd[i].fd, &efds);
444 }
445
446 /* examine fd sets */
447 rc = select (maxfd + 1, &rfds, &wfds, &efds, ptv);
448 if (rc < 0)
449 return rc;
450
451 /* establish results */
452 rc = 0;
453 for (i = 0; i < nfd; i++)
454 {
455 pfd[i].revents = (pfd[i].fd < 0
456 ? 0
457 : compute_revents (pfd[i].fd, pfd[i].events,
458 &rfds, &wfds, &efds));
459 rc += pfd[i].revents != 0;
460 }
461
462 return rc;
463 #else
464 static struct timeval tv0;
465 static HANDLE hEvent;
466 WSANETWORKEVENTS ev;
467 HANDLE h, handle_array[FD_SETSIZE + 2];
468 DWORD ret, wait_timeout, nhandles;
469 fd_set rfds, wfds, xfds;
470 BOOL poll_again;
471 MSG msg;
472 int rc = 0;
473 nfds_t i;
474
475 if (nfd > INT_MAX || timeout < -1)
476 {
477 errno = EINVAL;
478 return -1;
479 }
480
481 if (!hEvent)
482 hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
483
484 restart:
485 handle_array[0] = hEvent;
486 nhandles = 1;
487 FD_ZERO (&rfds);
488 FD_ZERO (&wfds);
489 FD_ZERO (&xfds);
490
491 /* Classify socket handles and create fd sets. */
492 for (i = 0; i < nfd; i++)
493 {
494 int sought = pfd[i].events;
495 pfd[i].revents = 0;
496 if (pfd[i].fd < 0)
497 continue;
498 if (!(sought & (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM | POLLWRBAND
499 | POLLPRI | POLLRDBAND)))
500 continue;
501
502 h = (HANDLE) _get_osfhandle (pfd[i].fd);
503 assure (h != NULL);
504 if (IsSocketHandle (h))
505 {
506 int requested = FD_CLOSE;
507
508 /* see above; socket handles are mapped onto select. */
509 if (sought & (POLLIN | POLLRDNORM))
510 {
511 requested |= FD_READ | FD_ACCEPT;
512 FD_SET ((SOCKET) h, &rfds);
513 }
514 if (sought & (POLLOUT | POLLWRNORM | POLLWRBAND))
515 {
516 requested |= FD_WRITE | FD_CONNECT;
517 FD_SET ((SOCKET) h, &wfds);
518 }
519 if (sought & (POLLPRI | POLLRDBAND))
520 {
521 requested |= FD_OOB;
522 FD_SET ((SOCKET) h, &xfds);
523 }
524
525 if (requested)
526 WSAEventSelect ((SOCKET) h, hEvent, requested);
527 }
528 else
529 {
530 /* Poll now. If we get an event, do not poll again. Also,
531 screen buffer handles are waitable, and they'll block until
532 a character is available. windows_compute_revents eliminates
533 bits for the "wrong" direction. */
534 pfd[i].revents = windows_compute_revents (h, &sought);
535 if (sought)
536 handle_array[nhandles++] = h;
537 if (pfd[i].revents)
538 timeout = 0;
539 }
540 }
541
542 if (select (0, &rfds, &wfds, &xfds, &tv0) > 0)
543 {
544 /* Do MsgWaitForMultipleObjects anyway to dispatch messages, but
545 no need to call select again. */
546 poll_again = FALSE;
547 wait_timeout = 0;
548 }
549 else
550 {
551 poll_again = TRUE;
552 if (timeout == INFTIM)
553 wait_timeout = INFINITE;
554 else
555 wait_timeout = timeout;
556 }
557
558 for (;;)
559 {
560 ret = MsgWaitForMultipleObjects (nhandles, handle_array, FALSE,
561 wait_timeout, QS_ALLINPUT);
562
563 if (ret == WAIT_OBJECT_0 + nhandles)
564 {
565 /* new input of some other kind */
566 BOOL bRet;
567 while ((bRet = PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) != 0)
568 {
569 TranslateMessage (&msg);
570 DispatchMessage (&msg);
571 }
572 }
573 else
574 break;
575 }
576
577 if (poll_again)
578 select (0, &rfds, &wfds, &xfds, &tv0);
579
580 /* Place a sentinel at the end of the array. */
581 handle_array[nhandles] = NULL;
582 nhandles = 1;
583 for (i = 0; i < nfd; i++)
584 {
585 int happened;
586
587 if (pfd[i].fd < 0)
588 continue;
589 if (!(pfd[i].events & (POLLIN | POLLRDNORM |
590 POLLOUT | POLLWRNORM | POLLWRBAND)))
591 continue;
592
593 h = (HANDLE) _get_osfhandle (pfd[i].fd);
594 if (h != handle_array[nhandles])
595 {
596 /* It's a socket. */
597 WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
598 WSAEventSelect ((SOCKET) h, 0, 0);
599
600 /* If we're lucky, WSAEnumNetworkEvents already provided a way
601 to distinguish FD_READ and FD_ACCEPT; this saves a recv later. */
602 if (FD_ISSET ((SOCKET) h, &rfds)
603 && !(ev.lNetworkEvents & (FD_READ | FD_ACCEPT)))
604 ev.lNetworkEvents |= FD_READ | FD_ACCEPT;
605 if (FD_ISSET ((SOCKET) h, &wfds))
606 ev.lNetworkEvents |= FD_WRITE | FD_CONNECT;
607 if (FD_ISSET ((SOCKET) h, &xfds))
608 ev.lNetworkEvents |= FD_OOB;
609
610 happened = windows_compute_revents_socket ((SOCKET) h, pfd[i].events,
611 ev.lNetworkEvents);
612 }
613 else
614 {
615 /* Not a socket. */
616 int sought = pfd[i].events;
617 happened = windows_compute_revents (h, &sought);
618 nhandles++;
619 }
620
621 if ((pfd[i].revents |= happened) != 0)
622 rc++;
623 }
624
625 if (!rc && timeout == INFTIM)
626 {
627 SleepEx (1, TRUE);
628 goto restart;
629 }
630
631 return rc;
632 #endif
633 }
634