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