00bf2c67d520be81f29e13472873caf299914b41
[gnulib.git] / lib / winsock-select.c
1 /* Emulation for select(2)
2    Contributed by Paolo Bonzini.
3
4    Copyright 2008 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 2, 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, write to the Free Software Foundation,
20    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
21
22 #include <config.h>
23 #include <alloca.h>
24
25 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
26 #include <sys/types.h>
27 #include <stdbool.h>
28 #include <errno.h>
29 #include <limits.h>
30
31 #include <winsock2.h>
32 #include <windows.h>
33 #include <io.h>
34 #include <stdio.h>
35 #include <conio.h>
36 #include <time.h>
37
38 struct bitset {
39   unsigned char in[FD_SETSIZE / CHAR_BIT];
40   unsigned char out[FD_SETSIZE / CHAR_BIT];
41 };
42
43 /* Declare data structures for ntdll functions.  */
44 typedef struct _FILE_PIPE_LOCAL_INFORMATION {
45   ULONG NamedPipeType;
46   ULONG NamedPipeConfiguration;
47   ULONG MaximumInstances;
48   ULONG CurrentInstances;
49   ULONG InboundQuota;
50   ULONG ReadDataAvailable;
51   ULONG OutboundQuota;
52   ULONG WriteQuotaAvailable;
53   ULONG NamedPipeState;
54   ULONG NamedPipeEnd;
55 } FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION;
56
57 typedef struct _IO_STATUS_BLOCK
58 {
59   union {
60     DWORD Status;
61     PVOID Pointer;
62   } u;
63   ULONG_PTR Information;
64 } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
65
66 typedef enum _FILE_INFORMATION_CLASS {
67   FilePipeLocalInformation = 24
68 } FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
69
70 typedef DWORD (WINAPI *PNtQueryInformationFile)
71          (HANDLE, IO_STATUS_BLOCK *, VOID *, ULONG, FILE_INFORMATION_CLASS);
72
73 #ifndef PIPE_BUF
74 #define PIPE_BUF        512
75 #endif
76
77 /* Compute output fd_sets for libc descriptor FD (whose Win32 handle is H).  */
78
79 static int
80 win32_poll_handle (HANDLE h, int fd, struct bitset *rbits, struct bitset *wbits,
81                    struct bitset *xbits)
82 {
83   BOOL read, write, except;
84   int i, ret;
85   INPUT_RECORD *irbuffer;
86   DWORD avail, nbuffer;
87   BOOL bRet;
88   IO_STATUS_BLOCK iosb;
89   FILE_PIPE_LOCAL_INFORMATION fpli;
90   static PNtQueryInformationFile NtQueryInformationFile;
91   static BOOL once_only;
92
93   read = write = except = FALSE;
94   switch (GetFileType (h))
95     {
96     case FILE_TYPE_PIPE:
97       if (!once_only)
98         {
99           NtQueryInformationFile = (PNtQueryInformationFile)
100             GetProcAddress (GetModuleHandle ("ntdll.dll"),
101                             "NtQueryInformationFile");
102           once_only = TRUE;
103         }
104
105       if (PeekNamedPipe (h, NULL, 0, NULL, &avail, NULL) != 0)
106         {
107           if (avail)
108             read = TRUE;
109         }
110
111       else
112         {
113           /* It was the write-end of the pipe.  Check if it is writable.
114              If NtQueryInformationFile fails, optimistically assume the pipe is
115              writable.  This could happen on Win9x, where NtQueryInformationFile
116              is not available, or if we inherit a pipe that doesn't permit
117              FILE_READ_ATTRIBUTES access on the write end (I think this should
118              not happen since WinXP SP2; WINE seems fine too).  Otherwise,
119              ensure that enough space is available for atomic writes.  */
120           memset (&iosb, 0, sizeof (iosb));
121           memset (&fpli, 0, sizeof (fpli));
122
123           if (!NtQueryInformationFile
124               || NtQueryInformationFile (h, &iosb, &fpli, sizeof (fpli),
125                                          FilePipeLocalInformation)
126               || fpli.WriteQuotaAvailable >= PIPE_BUF
127               || (fpli.OutboundQuota < PIPE_BUF &&
128                   fpli.WriteQuotaAvailable == fpli.OutboundQuota))
129             write = TRUE;
130         }
131       break;
132
133     case FILE_TYPE_CHAR:
134       ret = WaitForSingleObject (h, 0);
135       write = TRUE;
136       if (ret == WAIT_OBJECT_0)
137         {
138           nbuffer = avail = 0;
139           bRet = GetNumberOfConsoleInputEvents (h, &nbuffer);
140           if (!bRet || nbuffer == 0)
141             except = TRUE;
142
143           irbuffer = (INPUT_RECORD *) alloca (nbuffer * sizeof (INPUT_RECORD));
144           bRet = PeekConsoleInput (h, irbuffer, nbuffer, &avail);
145           if (!bRet || avail == 0)
146             except = TRUE;
147
148           for (i = 0; i < avail; i++)
149             if (irbuffer[i].EventType == KEY_EVENT)
150               read = TRUE;
151         }
152       break;
153
154     default:
155       ret = WaitForSingleObject (h, 0);
156       write = TRUE;
157       if (ret == WAIT_OBJECT_0)
158         read = TRUE;
159
160       break;
161     }
162
163   ret = 0;
164   if (read && (rbits->in[fd / CHAR_BIT] & (1 << (fd & (CHAR_BIT - 1)))))
165     {
166       rbits->out[fd / CHAR_BIT] |= (1 << (fd & (CHAR_BIT - 1)));
167       ret++;
168     }
169
170   if (write && (wbits->in[fd / CHAR_BIT] & (1 << (fd & (CHAR_BIT - 1)))))
171     {
172       wbits->out[fd / CHAR_BIT] |= (1 << (fd & (CHAR_BIT - 1)));
173       ret++;
174     }
175
176   if (except && (xbits->in[fd / CHAR_BIT] & (1 << (fd & (CHAR_BIT - 1)))))
177     {
178       xbits->out[fd / CHAR_BIT] |= (1 << (fd & (CHAR_BIT - 1)));
179       ret++;
180     }
181
182   return ret;
183 }
184
185 int
186 rpl_select (int nfds, fd_set *rfds, fd_set *wfds, fd_set *xfds,
187             struct timeval *timeout)
188 {
189   static struct timeval tv0;
190   static HANDLE hEvent;
191   HANDLE h, handle_array[FD_SETSIZE + 2];
192   fd_set handle_rfds, handle_wfds, handle_xfds;
193   struct bitset rbits, wbits, xbits;
194   unsigned char anyfds_in[FD_SETSIZE / CHAR_BIT];
195   DWORD ret, wait_timeout, nhandles, nsock;
196   MSG msg;
197   int i, fd, rc;
198
199   if (nfds > FD_SETSIZE)
200     nfds = FD_SETSIZE;
201
202   if (!timeout)
203     wait_timeout = INFINITE;
204   else
205     {
206       wait_timeout = timeout->tv_sec + timeout->tv_usec / 1000;
207
208       /* select is also used as a portable usleep.  */
209       if (!rfds && !wfds && !xfds)
210         {
211           Sleep (wait_timeout);
212           return 0;
213         }
214     }
215
216   if (!hEvent)
217     hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
218
219   handle_array[0] = hEvent;
220   nhandles = 1;
221   nsock = 0;
222
223   /* Copy descriptors to bitsets.  */
224   memset (&rbits, 0, sizeof (rbits));
225   memset (&wbits, 0, sizeof (wbits));
226   memset (&xbits, 0, sizeof (xbits));
227   memset (anyfds_in, 0, sizeof (anyfds_in));
228   if (rfds)
229     for (i = 0; i < rfds->fd_count; i++)
230       {
231         fd = rfds->fd_array[i];
232         rbits.in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
233         anyfds_in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
234       }
235   else
236     rfds = (fd_set *) alloca (sizeof (fd_set));
237
238   if (wfds)
239     for (i = 0; i < wfds->fd_count; i++)
240       {
241         fd = wfds->fd_array[i];
242         wbits.in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
243         anyfds_in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
244       }
245   else
246     wfds = (fd_set *) alloca (sizeof (fd_set));
247
248   if (xfds)
249     for (i = 0; i < xfds->fd_count; i++)
250       {
251         fd = xfds->fd_array[i];
252         xbits.in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
253         anyfds_in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
254       }
255   else
256     xfds = (fd_set *) alloca (sizeof (fd_set));
257
258   /* Zero all the fd_sets, including the application's.  */
259   FD_ZERO (rfds);
260   FD_ZERO (wfds);
261   FD_ZERO (xfds);
262   FD_ZERO (&handle_rfds);
263   FD_ZERO (&handle_wfds);
264   FD_ZERO (&handle_xfds);
265
266   /* Classify handles.  Create fd sets for sockets, poll the others. */
267   for (i = 0; i < nfds; i++)
268     {
269       WSANETWORKEVENTS ev;
270
271       if ((anyfds_in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1)))) == 0)
272         continue;
273
274       h = (HANDLE) _get_osfhandle (i);
275       if (!h)
276         {
277           errno = EBADF;
278           return -1;
279         }
280
281       /* Under Wine, it seems that getsockopt returns 0 for pipes too.
282          WSAEnumNetworkEvents instead distinguishes the two correctly.  */
283       ev.lNetworkEvents = 0xDEADBEEF;
284       WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
285       if (ev.lNetworkEvents != 0xDEADBEEF)
286         {
287           int requested = FD_CLOSE;
288
289           /* See above; socket handles are mapped onto select, but we
290              need to map descriptors to handles.  */
291           if (rbits.in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
292             {
293               requested |= FD_READ | FD_ACCEPT;
294               FD_SET ((SOCKET) h, rfds);
295               FD_SET ((SOCKET) h, &handle_rfds);
296             }
297           if (wbits.in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
298             {
299               requested |= FD_WRITE | FD_CONNECT;
300               FD_SET ((SOCKET) h, wfds);
301               FD_SET ((SOCKET) h, &handle_wfds);
302             }
303           if (xbits.in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
304             {
305               requested |= FD_OOB;
306               FD_SET ((SOCKET) h, xfds);
307               FD_SET ((SOCKET) h, &handle_xfds);
308             }
309
310           WSAEventSelect ((SOCKET) h, hEvent, requested);
311           nsock++;
312         }
313       else
314         {
315           handle_array[nhandles++] = h;
316
317           /* Poll now.  If we get an event, do not wait below.  */
318           if (wait_timeout != 0
319               && win32_poll_handle (h, i, &rbits, &wbits, &xbits))
320             wait_timeout = 0;
321         }
322     }
323
324   if (wait_timeout == 0 || nsock == 0)
325     rc = 0;
326   else
327     {
328       /* See if we need to wait in the loop below.  If any select is ready,
329          do MsgWaitForMultipleObjects anyway to dispatch messages, but
330          no need to call select again.  */
331       rc = select (0, &handle_rfds, &handle_wfds, &handle_xfds, &tv0);
332       if (rc == 0)
333         {
334           /* Restore the fd_sets for the other select we do below.  */
335           memcpy (&handle_rfds, rfds, sizeof (fd_set));
336           memcpy (&handle_wfds, wfds, sizeof (fd_set));
337           memcpy (&handle_xfds, xfds, sizeof (fd_set));
338         }
339       else
340         wait_timeout = 0;
341     }
342
343   for (;;)
344     {
345       ret = MsgWaitForMultipleObjects (nhandles, handle_array, FALSE,
346                                        wait_timeout, QS_ALLINPUT);
347
348       if (ret == WAIT_OBJECT_0 + nhandles)
349         {
350           /* new input of some other kind */
351           BOOL bRet;
352           while ((bRet = PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) != 0)
353             {
354               TranslateMessage (&msg);
355               DispatchMessage (&msg);
356             }
357         }
358       else
359         break;
360     }
361
362   /* If we haven't done it yet, check the status of the sockets.  */
363   if (rc == 0 && nsock > 0)
364     rc = select (0, &handle_rfds, &handle_wfds, &handle_xfds, &tv0);
365
366   /* Now fill in the results.  */
367   FD_ZERO (rfds);
368   FD_ZERO (wfds);
369   FD_ZERO (xfds);
370
371   /* Place a sentinel at the end of the array.  */
372   handle_array[nhandles] = NULL;
373   nhandles = 1;
374   for (i = 0; i < nfds; i++)
375     {
376       if ((anyfds_in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1)))) == 0)
377         continue;
378
379       h = (HANDLE) _get_osfhandle (i);
380       if (h != handle_array[nhandles])
381         {
382           /* Perform handle->descriptor mapping.  Don't update rc, as these
383              results are counted in the return value of Winsock's select.  */
384           WSAEventSelect ((SOCKET) h, NULL, 0);
385           if (FD_ISSET (h, &handle_rfds))
386             FD_SET (i, rfds);
387           if (FD_ISSET (h, &handle_wfds))
388             FD_SET (i, wfds);
389           if (FD_ISSET (h, &handle_xfds))
390             FD_SET (i, xfds);
391         }
392       else
393         {
394           /* Not a socket.  */
395           nhandles++;
396           win32_poll_handle (h, i, &rbits, &wbits, &xbits);
397           if (rbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
398             {
399               rc++;
400               FD_SET (i, rfds);
401             }
402           if (wbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
403             {
404               rc++;
405               FD_SET (i, wfds);
406             }
407           if (xbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
408             {
409               rc++;
410               FD_SET (i, xfds);
411             }
412         }
413     }
414
415   return rc;
416 }
417
418 #endif /* Native Win32.  */