1 /* Emulation for select(2)
2    Contributed by Paolo Bonzini.
3 
4    Copyright 2008-2013 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 
46 struct 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.  */
52 typedef 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 
65 typedef 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 
74 typedef enum _FILE_INFORMATION_CLASS {
75   FilePipeLocalInformation = 24
76 } FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
77 
78 typedef 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 
89 static BOOL
IsSocketHandle(HANDLE h)90 IsSocketHandle (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 
107 static int
windows_poll_handle(HANDLE h,int fd,struct bitset * rbits,struct bitset * wbits,struct bitset * xbits)108 windows_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 
241 int
rpl_select(int nfds,fd_set * rfds,fd_set * wfds,fd_set * xfds,struct timeval * timeout)242 rpl_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 
391 restart:
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 
515 int
rpl_select(int nfds,fd_set * rfds,fd_set * wfds,fd_set * xfds,struct timeval * timeout)516 rpl_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