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