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