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