1 /**
2  * Copyright © 2007-2012 Rémi Denis-Courmont
3  * Copyright © 2014-2015 VideoLabs SAS
4  *
5  * Author: Rémi Denis-Courmont
6  *         Jonathan Calmels <jbjcalmels@gmail.com>
7  *
8  * Permission to use, copy, modify, and distribute this software for any
9  * purpose with or without fee is hereby granted, provided that the above
10  * copyright notice and this permission notice appear in all copies.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19  */
20 
21 #ifdef HAVE_CONFIG_H
22 # include "config.h"
23 #endif
24 
25 #include <assert.h>
26 #include <errno.h>
27 #include <string.h>
28 
29 #include "compat.h"
30 #include "utils.h"
31 
32 #ifndef HAVE_POLL
poll(struct pollfd * fds,unsigned nfds,int timeout)33 int poll(struct pollfd *fds, unsigned nfds, int timeout)
34 {
35     DWORD to = (timeout >= 0) ? (DWORD)timeout : INFINITE;
36 
37     if (nfds == 0)
38     {    /* WSAWaitForMultipleEvents() does not allow zero events */
39         if (SleepEx(to, TRUE))
40         {
41             errno = EINTR;
42             return -1;
43         }
44         return 0;
45     }
46 
47     WSAEVENT *evts = malloc(nfds * sizeof (WSAEVENT));
48     if (evts == NULL)
49         return -1; /* ENOMEM */
50 
51     DWORD ret = WSA_WAIT_FAILED;
52     for (unsigned i = 0; i < nfds; i++)
53     {
54         SOCKET fd = fds[i].fd;
55         long mask = FD_CLOSE;
56         fd_set rdset, wrset, exset;
57 
58         FD_ZERO(&rdset);
59         FD_ZERO(&wrset);
60         FD_ZERO(&exset);
61         FD_SET(fd, &exset);
62 
63         if (fds[i].events & POLLRDNORM)
64         {
65             mask |= FD_READ | FD_ACCEPT;
66             FD_SET(fd, &rdset);
67         }
68         if (fds[i].events & POLLWRNORM)
69         {
70             mask |= FD_WRITE | FD_CONNECT;
71             FD_SET(fd, &wrset);
72         }
73         if (fds[i].events & POLLPRI)
74             mask |= FD_OOB;
75 
76         fds[i].revents = 0;
77 
78         evts[i] = WSACreateEvent();
79         if (evts[i] == WSA_INVALID_EVENT)
80         {
81             while (i > 0)
82                 WSACloseEvent(evts[--i]);
83             free(evts);
84             errno = ENOMEM;
85             return -1;
86         }
87 
88         if (WSAEventSelect(fds[i].fd, evts[i], mask)
89          && WSAGetLastError() == WSAENOTSOCK)
90             fds[i].revents |= POLLNVAL;
91 
92         struct timeval tv = { 0, 0 };
93         /* By its horrible design, WSAEnumNetworkEvents() only enumerates
94          * events that were not already signaled (i.e. it is edge-triggered).
95          * WSAPoll() would be better in this respect, but worse in others.
96          * So use WSAEnumNetworkEvents() after manually checking for pending
97          * events. */
98         if (select(0, &rdset, &wrset, &exset, &tv) > 0)
99         {
100             if (FD_ISSET(fd, &rdset))
101                 fds[i].revents |= fds[i].events & POLLRDNORM;
102             if (FD_ISSET(fd, &wrset))
103                 fds[i].revents |= fds[i].events & POLLWRNORM;
104             if (FD_ISSET(fd, &exset))
105                 /* To add pain to injury, POLLERR and POLLPRI cannot be
106                  * distinguished here. */
107                 fds[i].revents |= POLLERR | (fds[i].events & POLLPRI);
108         }
109 
110         if (fds[i].revents != 0 && ret == WSA_WAIT_FAILED)
111             ret = WSA_WAIT_EVENT_0 + i;
112     }
113 
114     if (ret == WSA_WAIT_FAILED)
115         ret = WSAWaitForMultipleEvents(nfds, evts, FALSE, to, TRUE);
116 
117     unsigned count = 0;
118     for (unsigned i = 0; i < nfds; i++)
119     {
120         WSANETWORKEVENTS ne;
121 
122         if (WSAEnumNetworkEvents(fds[i].fd, evts[i], &ne))
123             memset(&ne, 0, sizeof (ne));
124         WSAEventSelect(fds[i].fd, evts[i], 0);
125         WSACloseEvent(evts[i]);
126 
127         if (ne.lNetworkEvents & FD_CONNECT)
128         {
129             fds[i].revents |= POLLWRNORM;
130             if (ne.iErrorCode[FD_CONNECT_BIT] != 0)
131                 fds[i].revents |= POLLERR;
132         }
133         if (ne.lNetworkEvents & FD_CLOSE)
134         {
135             fds[i].revents |= (fds[i].events & POLLRDNORM) | POLLHUP;
136             if (ne.iErrorCode[FD_CLOSE_BIT] != 0)
137                 fds[i].revents |= POLLERR;
138         }
139         if (ne.lNetworkEvents & FD_ACCEPT)
140         {
141             fds[i].revents |= POLLRDNORM;
142             if (ne.iErrorCode[FD_ACCEPT_BIT] != 0)
143                 fds[i].revents |= POLLERR;
144         }
145         if (ne.lNetworkEvents & FD_OOB)
146         {
147             fds[i].revents |= POLLPRI;
148             if (ne.iErrorCode[FD_OOB_BIT] != 0)
149                 fds[i].revents |= POLLERR;
150         }
151         if (ne.lNetworkEvents & FD_READ)
152         {
153             fds[i].revents |= POLLRDNORM;
154             if (ne.iErrorCode[FD_READ_BIT] != 0)
155                 fds[i].revents |= POLLERR;
156         }
157         if (ne.lNetworkEvents & FD_WRITE)
158         {
159             fds[i].revents |= POLLWRNORM;
160             if (ne.iErrorCode[FD_WRITE_BIT] != 0)
161                 fds[i].revents |= POLLERR;
162         }
163         count += fds[i].revents != 0;
164     }
165 
166     free(evts);
167 
168     if (count == 0 && ret == WSA_WAIT_IO_COMPLETION)
169     {
170         errno = EINTR;
171         return -1;
172     }
173     return count;
174 }
175 
176 #endif
177