root/maint/gnulib/lib/poll.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. IsConsoleHandle
  2. IsSocketHandle
  3. windows_compute_revents
  4. windows_compute_revents_socket
  5. compute_revents
  6. poll

   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 file is free software: you can redistribute it and/or modify
   9    it under the terms of the GNU Lesser General Public License as
  10    published by the Free Software Foundation; either version 2.1 of the
  11    License, or (at your option) any later version.
  12 
  13    This file 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
  19    along 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 115 {
 116   DWORD mode;
 117   return GetConsoleMode (h, &mode) != 0;
 118 }
 119 
 120 static BOOL
 121 IsSocketHandle (HANDLE h)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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 }

/* [previous][next][first][last][top][bottom][index][help] */