gsasl  1.10.0
About: GNU SASL is an implementation of the Simple Authentication and Security Layer (SASL). Development version.
  Fossies Dox: gsasl-1.10.0.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

poll.c
Go to the documentation of this file.
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 General Public License as published by
10  the Free Software Foundation; either version 3, 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 General Public License for more details.
17 
18  You should have received a copy of the GNU 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 
114 static BOOL IsConsoleHandle (HANDLE h)
115 {
116  DWORD mode;
117  return GetConsoleMode (h, &mode) != 0;
118 }
119 
120 static BOOL
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
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
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
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
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 |
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 }
#define assure(E)
Definition: assure.h:54
const char * msg
Definition: gai_strerror.c:53
#define alloca(size)
Definition: getopt.c:56
#define ECONNABORTED
Definition: errno.in.h:223
#define ENETRESET
Definition: errno.in.h:218
void error(int status, int errnum, const char *message,...)
Definition: error.c:295
#define NULL
Definition: stddef.in.h:72
#define CreateEvent
int ioctl(int fd, int request,...)
Definition: ioctl.c:76
int rc
Definition: error.c:42
static int compute_revents(int fd, int sought, fd_set *rfds, fd_set *wfds, fd_set *efds)
Definition: poll.c:314
#define MSG_PEEK
Definition: poll.c:74
int poll(struct pollfd *pfd, nfds_t nfd, int timeout)
Definition: poll.c:368
#define INFTIM
Definition: poll.c:69
unsigned long nfds_t
Definition: poll.in.h:87
#define POLLHUP
Definition: poll.in.h:71
#define POLLWRBAND
Definition: poll.in.h:76
#define POLLRDBAND
Definition: poll.in.h:74
#define POLLIN
Definition: poll.in.h:67
#define POLLRDNORM
Definition: poll.in.h:73
#define POLLOUT
Definition: poll.in.h:69
#define POLLERR
Definition: poll.in.h:70
#define POLLPRI
Definition: poll.in.h:68
#define POLLWRNORM
Definition: poll.in.h:75
Definition: poll.in.h:81
int fd
Definition: poll.in.h:82
short revents
Definition: poll.in.h:84
short events
Definition: poll.in.h:83
long int tv_usec
Definition: sys_time.in.h:78
time_t tv_sec
Definition: sys_time.in.h:77