1/* Emulation for select(2)
2   Contributed by Paolo Bonzini.
3
4   Copyright 2008-2014 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 <http://www.gnu.org/licenses/>.  */
20
21#include <config.h>
22#include <alloca.h>
23#include <assert.h>
24
25#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
26/* Native Windows.  */
27
28#include <sys/types.h>
29#include <errno.h>
30#include <limits.h>
31
32#include <winsock2.h>
33#include <windows.h>
34#include <io.h>
35#include <stdio.h>
36#include <conio.h>
37#include <time.h>
38
39/* Get the overridden 'struct timeval'.  */
40#include <sys/time.h>
41
42#include "msvc-nothrow.h"
43
44#undef select
45
46struct bitset {
47  unsigned char in[FD_SETSIZE / CHAR_BIT];
48  unsigned char out[FD_SETSIZE / CHAR_BIT];
49};
50
51/* Declare data structures for ntdll functions.  */
52typedef struct _FILE_PIPE_LOCAL_INFORMATION {
53  ULONG NamedPipeType;
54  ULONG NamedPipeConfiguration;
55  ULONG MaximumInstances;
56  ULONG CurrentInstances;
57  ULONG InboundQuota;
58  ULONG ReadDataAvailable;
59  ULONG OutboundQuota;
60  ULONG WriteQuotaAvailable;
61  ULONG NamedPipeState;
62  ULONG NamedPipeEnd;
63} FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION;
64
65typedef struct _IO_STATUS_BLOCK
66{
67  union {
68    DWORD Status;
69    PVOID Pointer;
70  } u;
71  ULONG_PTR Information;
72} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
73
74typedef enum _FILE_INFORMATION_CLASS {
75  FilePipeLocalInformation = 24
76} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
77
78typedef DWORD (WINAPI *PNtQueryInformationFile)
79         (HANDLE, IO_STATUS_BLOCK *, VOID *, ULONG, FILE_INFORMATION_CLASS);
80
81#ifndef PIPE_BUF
82#define PIPE_BUF        512
83#endif
84
85/* Optimized test whether a HANDLE refers to a console.
86   See <http://lists.gnu.org/archive/html/bug-gnulib/2009-08/msg00065.html>.  */
87#define IsConsoleHandle(h) (((intptr_t) (h) & 3) == 3)
88
89static BOOL
90IsSocketHandle (HANDLE h)
91{
92  WSANETWORKEVENTS ev;
93
94  if (IsConsoleHandle (h))
95    return FALSE;
96
97  /* Under Wine, it seems that getsockopt returns 0 for pipes too.
98     WSAEnumNetworkEvents instead distinguishes the two correctly.  */
99  ev.lNetworkEvents = 0xDEADBEEF;
100  WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
101  return ev.lNetworkEvents != 0xDEADBEEF;
102}
103
104/* Compute output fd_sets for libc descriptor FD (whose Windows handle is
105   H).  */
106
107static int
108windows_poll_handle (HANDLE h, int fd,
109                     struct bitset *rbits,
110                     struct bitset *wbits,
111                     struct bitset *xbits)
112{
113  BOOL read, write, except;
114  int i, ret;
115  INPUT_RECORD *irbuffer;
116  DWORD avail, nbuffer;
117  BOOL bRet;
118  IO_STATUS_BLOCK iosb;
119  FILE_PIPE_LOCAL_INFORMATION fpli;
120  static PNtQueryInformationFile NtQueryInformationFile;
121  static BOOL once_only;
122
123  read = write = except = FALSE;
124  switch (GetFileType (h))
125    {
126    case FILE_TYPE_DISK:
127      read = TRUE;
128      write = TRUE;
129      break;
130
131    case FILE_TYPE_PIPE:
132      if (!once_only)
133        {
134          NtQueryInformationFile = (PNtQueryInformationFile)
135            GetProcAddress (GetModuleHandle ("ntdll.dll"),
136                            "NtQueryInformationFile");
137          once_only = TRUE;
138        }
139
140      if (PeekNamedPipe (h, NULL, 0, NULL, &avail, NULL) != 0)
141        {
142          if (avail)
143            read = TRUE;
144        }
145      else if (GetLastError () == ERROR_BROKEN_PIPE)
146        ;
147
148      else
149        {
150          /* It was the write-end of the pipe.  Check if it is writable.
151             If NtQueryInformationFile fails, optimistically assume the pipe is
152             writable.  This could happen on Windows 9x, where
153             NtQueryInformationFile is not available, or if we inherit a pipe
154             that doesn't permit FILE_READ_ATTRIBUTES access on the write end
155             (I think this should not happen since Windows XP SP2; WINE seems
156             fine too).  Otherwise, ensure that enough space is available for
157             atomic writes.  */
158          memset (&iosb, 0, sizeof (iosb));
159          memset (&fpli, 0, sizeof (fpli));
160
161          if (!NtQueryInformationFile
162              || NtQueryInformationFile (h, &iosb, &fpli, sizeof (fpli),
163                                         FilePipeLocalInformation)
164              || fpli.WriteQuotaAvailable >= PIPE_BUF
165              || (fpli.OutboundQuota < PIPE_BUF &&
166                  fpli.WriteQuotaAvailable == fpli.OutboundQuota))
167            write = TRUE;
168        }
169      break;
170
171    case FILE_TYPE_CHAR:
172      write = TRUE;
173      if (!(rbits->in[fd / CHAR_BIT] & (1 << (fd & (CHAR_BIT - 1)))))
174        break;
175
176      ret = WaitForSingleObject (h, 0);
177      if (ret == WAIT_OBJECT_0)
178        {
179          if (!IsConsoleHandle (h))
180            {
181              read = TRUE;
182              break;
183            }
184
185          nbuffer = avail = 0;
186          bRet = GetNumberOfConsoleInputEvents (h, &nbuffer);
187
188          /* Screen buffers handles are filtered earlier.  */
189          assert (bRet);
190          if (nbuffer == 0)
191            {
192              except = TRUE;
193              break;
194            }
195
196          irbuffer = (INPUT_RECORD *) alloca (nbuffer * sizeof (INPUT_RECORD));
197          bRet = PeekConsoleInput (h, irbuffer, nbuffer, &avail);
198          if (!bRet || avail == 0)
199            {
200              except = TRUE;
201              break;
202            }
203
204          for (i = 0; i < avail; i++)
205            if (irbuffer[i].EventType == KEY_EVENT)
206              read = TRUE;
207        }
208      break;
209
210    default:
211      ret = WaitForSingleObject (h, 0);
212      write = TRUE;
213      if (ret == WAIT_OBJECT_0)
214        read = TRUE;
215
216      break;
217    }
218
219  ret = 0;
220  if (read && (rbits->in[fd / CHAR_BIT] & (1 << (fd & (CHAR_BIT - 1)))))
221    {
222      rbits->out[fd / CHAR_BIT] |= (1 << (fd & (CHAR_BIT - 1)));
223      ret++;
224    }
225
226  if (write && (wbits->in[fd / CHAR_BIT] & (1 << (fd & (CHAR_BIT - 1)))))
227    {
228      wbits->out[fd / CHAR_BIT] |= (1 << (fd & (CHAR_BIT - 1)));
229      ret++;
230    }
231
232  if (except && (xbits->in[fd / CHAR_BIT] & (1 << (fd & (CHAR_BIT - 1)))))
233    {
234      xbits->out[fd / CHAR_BIT] |= (1 << (fd & (CHAR_BIT - 1)));
235      ret++;
236    }
237
238  return ret;
239}
240
241int
242rpl_select (int nfds, fd_set *rfds, fd_set *wfds, fd_set *xfds,
243            struct timeval *timeout)
244#undef timeval
245{
246  static struct timeval tv0;
247  static HANDLE hEvent;
248  HANDLE h, handle_array[FD_SETSIZE + 2];
249  fd_set handle_rfds, handle_wfds, handle_xfds;
250  struct bitset rbits, wbits, xbits;
251  unsigned char anyfds_in[FD_SETSIZE / CHAR_BIT];
252  DWORD ret, wait_timeout, nhandles, nsock, nbuffer;
253  MSG msg;
254  int i, fd, rc;
255
256  if (nfds > FD_SETSIZE)
257    nfds = FD_SETSIZE;
258
259  if (!timeout)
260    wait_timeout = INFINITE;
261  else
262    {
263      wait_timeout = timeout->tv_sec * 1000 + timeout->tv_usec / 1000;
264
265      /* select is also used as a portable usleep.  */
266      if (!rfds && !wfds && !xfds)
267        {
268          Sleep (wait_timeout);
269          return 0;
270        }
271    }
272
273  if (!hEvent)
274    hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
275
276  handle_array[0] = hEvent;
277  nhandles = 1;
278  nsock = 0;
279
280  /* Copy descriptors to bitsets.  At the same time, eliminate
281     bits in the "wrong" direction for console input buffers
282     and screen buffers, because screen buffers are waitable
283     and they will block until a character is available.  */
284  memset (&rbits, 0, sizeof (rbits));
285  memset (&wbits, 0, sizeof (wbits));
286  memset (&xbits, 0, sizeof (xbits));
287  memset (anyfds_in, 0, sizeof (anyfds_in));
288  if (rfds)
289    for (i = 0; i < rfds->fd_count; i++)
290      {
291        fd = rfds->fd_array[i];
292        h = (HANDLE) _get_osfhandle (fd);
293        if (IsConsoleHandle (h)
294            && !GetNumberOfConsoleInputEvents (h, &nbuffer))
295          continue;
296
297        rbits.in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
298        anyfds_in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
299      }
300  else
301    rfds = (fd_set *) alloca (sizeof (fd_set));
302
303  if (wfds)
304    for (i = 0; i < wfds->fd_count; i++)
305      {
306        fd = wfds->fd_array[i];
307        h = (HANDLE) _get_osfhandle (fd);
308        if (IsConsoleHandle (h)
309            && GetNumberOfConsoleInputEvents (h, &nbuffer))
310          continue;
311
312        wbits.in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
313        anyfds_in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
314      }
315  else
316    wfds = (fd_set *) alloca (sizeof (fd_set));
317
318  if (xfds)
319    for (i = 0; i < xfds->fd_count; i++)
320      {
321        fd = xfds->fd_array[i];
322        xbits.in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
323        anyfds_in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
324      }
325  else
326    xfds = (fd_set *) alloca (sizeof (fd_set));
327
328  /* Zero all the fd_sets, including the application's.  */
329  FD_ZERO (rfds);
330  FD_ZERO (wfds);
331  FD_ZERO (xfds);
332  FD_ZERO (&handle_rfds);
333  FD_ZERO (&handle_wfds);
334  FD_ZERO (&handle_xfds);
335
336  /* Classify handles.  Create fd sets for sockets, poll the others. */
337  for (i = 0; i < nfds; i++)
338    {
339      if ((anyfds_in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1)))) == 0)
340        continue;
341
342      h = (HANDLE) _get_osfhandle (i);
343      if (!h)
344        {
345          errno = EBADF;
346          return -1;
347        }
348
349      if (IsSocketHandle (h))
350        {
351          int requested = FD_CLOSE;
352
353          /* See above; socket handles are mapped onto select, but we
354             need to map descriptors to handles.  */
355          if (rbits.in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
356            {
357              requested |= FD_READ | FD_ACCEPT;
358              FD_SET ((SOCKET) h, rfds);
359              FD_SET ((SOCKET) h, &handle_rfds);
360            }
361          if (wbits.in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
362            {
363              requested |= FD_WRITE | FD_CONNECT;
364              FD_SET ((SOCKET) h, wfds);
365              FD_SET ((SOCKET) h, &handle_wfds);
366            }
367          if (xbits.in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
368            {
369              requested |= FD_OOB;
370              FD_SET ((SOCKET) h, xfds);
371              FD_SET ((SOCKET) h, &handle_xfds);
372            }
373
374          WSAEventSelect ((SOCKET) h, hEvent, requested);
375          nsock++;
376        }
377      else
378        {
379          handle_array[nhandles++] = h;
380
381          /* Poll now.  If we get an event, do not wait below.  */
382          if (wait_timeout != 0
383              && windows_poll_handle (h, i, &rbits, &wbits, &xbits))
384            wait_timeout = 0;
385        }
386    }
387
388  /* Place a sentinel at the end of the array.  */
389  handle_array[nhandles] = NULL;
390
391restart:
392  if (wait_timeout == 0 || nsock == 0)
393    rc = 0;
394  else
395    {
396      /* See if we need to wait in the loop below.  If any select is ready,
397         do MsgWaitForMultipleObjects anyway to dispatch messages, but
398         no need to call select again.  */
399      rc = select (0, &handle_rfds, &handle_wfds, &handle_xfds, &tv0);
400      if (rc == 0)
401        {
402          /* Restore the fd_sets for the other select we do below.  */
403          memcpy (&handle_rfds, rfds, sizeof (fd_set));
404          memcpy (&handle_wfds, wfds, sizeof (fd_set));
405          memcpy (&handle_xfds, xfds, sizeof (fd_set));
406        }
407      else
408        wait_timeout = 0;
409    }
410
411  for (;;)
412    {
413      ret = MsgWaitForMultipleObjects (nhandles, handle_array, FALSE,
414                                       wait_timeout, QS_ALLINPUT);
415
416      if (ret == WAIT_OBJECT_0 + nhandles)
417        {
418          /* new input of some other kind */
419          BOOL bRet;
420          while ((bRet = PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) != 0)
421            {
422              TranslateMessage (&msg);
423              DispatchMessage (&msg);
424            }
425        }
426      else
427        break;
428    }
429
430  /* If we haven't done it yet, check the status of the sockets.  */
431  if (rc == 0 && nsock > 0)
432    rc = select (0, &handle_rfds, &handle_wfds, &handle_xfds, &tv0);
433
434  if (nhandles > 1)
435    {
436      /* Count results that are not counted in the return value of select.  */
437      nhandles = 1;
438      for (i = 0; i < nfds; i++)
439        {
440          if ((anyfds_in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1)))) == 0)
441            continue;
442
443          h = (HANDLE) _get_osfhandle (i);
444          if (h == handle_array[nhandles])
445            {
446              /* Not a socket.  */
447              nhandles++;
448              windows_poll_handle (h, i, &rbits, &wbits, &xbits);
449              if (rbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1)))
450                  || wbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1)))
451                  || xbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
452                rc++;
453            }
454        }
455
456      if (rc == 0 && wait_timeout == INFINITE)
457        {
458          /* Sleep 1 millisecond to avoid busy wait and retry with the
459             original fd_sets.  */
460          memcpy (&handle_rfds, rfds, sizeof (fd_set));
461          memcpy (&handle_wfds, wfds, sizeof (fd_set));
462          memcpy (&handle_xfds, xfds, sizeof (fd_set));
463          SleepEx (1, TRUE);
464          goto restart;
465        }
466    }
467
468  /* Now fill in the results.  */
469  FD_ZERO (rfds);
470  FD_ZERO (wfds);
471  FD_ZERO (xfds);
472  nhandles = 1;
473  for (i = 0; i < nfds; i++)
474    {
475      if ((anyfds_in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1)))) == 0)
476        continue;
477
478      h = (HANDLE) _get_osfhandle (i);
479      if (h != handle_array[nhandles])
480        {
481          /* Perform handle->descriptor mapping.  */
482          WSAEventSelect ((SOCKET) h, NULL, 0);
483          if (FD_ISSET (h, &handle_rfds))
484            FD_SET (i, rfds);
485          if (FD_ISSET (h, &handle_wfds))
486            FD_SET (i, wfds);
487          if (FD_ISSET (h, &handle_xfds))
488            FD_SET (i, xfds);
489        }
490      else
491        {
492          /* Not a socket.  */
493          nhandles++;
494          if (rbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
495            FD_SET (i, rfds);
496          if (wbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
497            FD_SET (i, wfds);
498          if (xbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
499            FD_SET (i, xfds);
500        }
501    }
502
503  return rc;
504}
505
506#else /* ! Native Windows.  */
507
508#include <sys/select.h>
509#include <stddef.h> /* NULL */
510#include <errno.h>
511#include <unistd.h>
512
513#undef select
514
515int
516rpl_select (int nfds, fd_set *rfds, fd_set *wfds, fd_set *xfds,
517            struct timeval *timeout)
518{
519  int i;
520
521  /* FreeBSD 8.2 has a bug: it does not always detect invalid fds.  */
522  if (nfds < 0 || nfds > FD_SETSIZE)
523    {
524      errno = EINVAL;
525      return -1;
526    }
527  for (i = 0; i < nfds; i++)
528    {
529      if (((rfds && FD_ISSET (i, rfds))
530           || (wfds && FD_ISSET (i, wfds))
531           || (xfds && FD_ISSET (i, xfds)))
532          && dup2 (i, i) != i)
533        return -1;
534    }
535
536  /* Interix 3.5 has a bug: it does not support nfds == 0.  */
537  if (nfds == 0)
538    {
539      nfds = 1;
540      rfds = NULL;
541      wfds = NULL;
542      xfds = NULL;
543    }
544  return select (nfds, rfds, wfds, xfds, timeout);
545}
546
547#endif
548