1 /* This file is part of the Sofia-SIP package.
2
3 Copyright (C) 2005 Nokia Corporation.
4
5 Contact: Pekka Pessi <pekka.pessi@nokia.com>
6
7 This file is originally from GNU C library.
8
9 Copyright (C) 1994,1996,1997,1998,1999,2001,2002
10 Free Software Foundation, Inc.
11
12 This library is free software; you can redistribute it and/or
13 modify it under the terms of the GNU Lesser General Public
14 License as published by the Free Software Foundation; either
15 version 2.1 of the License, or (at your option) any later version.
16
17 This library is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 Lesser General Public License for more details.
21
22 You should have received a copy of the GNU Lesser General Public
23 License along with the GNU C Library; if not, write to the Free
24 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
25 02111-1307 USA. */
26
27 #include "config.h"
28
29 #if HAVE_SELECT
30
31 #if HAVE_SYS_SELECT_H
32 #include <sys/select.h>
33 #endif
34
35 #include "sofia-sip/su.h"
36
37 #if HAVE_ALLOCA_H
38 #include <alloca.h>
39 #endif
40
41 #if HAVE_SYS_TIME_H
42 #include <sys/time.h>
43 #endif
44
45 #include <string.h>
46
47 #include "sofia-sip/su_wait.h"
48
49 #undef NBBY
50 #undef NFDBITS
51 #undef FDSETSIZE
52 #undef roundup
53
54 #define NBBY 8 /* bits in a byte */
55 #define NFDBITS (sizeof(long) * NBBY) /* bits per mask */
56
57 #define FDSETSIZE(n) (((n) + NFDBITS - 1) / NFDBITS * (NFDBITS / NBBY))
58 #define roundup(n, x) (((n) + (x) - 1) / (x) * (x))
59
60 /* Emulated poll() using select().
61
62 This is used by su_wait().
63
64 Poll the file descriptors described by the NFDS structures starting at
65 FDS. If TIMEOUT is nonzero and not -1, allow TIMEOUT milliseconds for
66 an event to occur; if TIMEOUT is -1, block until an event occurs.
67 Returns the number of file descriptors with events, zero if timed out,
68 or -1 for errors. */
69
poll(struct pollfd * fds,nfds_t nfds,int timeout)70 int poll(struct pollfd *fds, nfds_t nfds, int timeout)
71 {
72 struct timeval tv;
73 struct pollfd *f;
74 int ready;
75 int maxfd = 0;
76
77 #if HAVE_ALLOCA_H
78 static int max_fd_size;
79 int bytes;
80 fd_set *rset, *wset, *xset;
81
82 if (!max_fd_size)
83 max_fd_size = getdtablesize ();
84
85 bytes = FDSETSIZE (max_fd_size);
86
87 rset = alloca (bytes);
88 wset = alloca (bytes);
89 xset = alloca (bytes);
90
91 /* We can't call FD_ZERO, since FD_ZERO only works with sets
92 of exactly __FD_SETSIZE size. */
93 memset (rset, 0, bytes);
94 memset (wset, 0, bytes);
95 memset (xset, 0, bytes);
96 #else
97 fd_set rset[1], wset[1], xset[1];
98
99 FD_ZERO(rset);
100 FD_ZERO(wset);
101 FD_ZERO(xset);
102 #endif
103
104 for (f = fds; f < &fds[nfds]; ++f)
105 {
106 f->revents = 0;
107 if (f->fd >= 0)
108 {
109 #if HAVE_ALLOCA_H
110 if (f->fd >= max_fd_size)
111 {
112 /* The user provides a file descriptor number which is higher
113 than the maximum we got from the `getdtablesize' call.
114 Maybe this is ok so enlarge the arrays. */
115 fd_set *nrset, *nwset, *nxset;
116 int nbytes;
117
118 max_fd_size = roundup (f->fd, NFDBITS);
119 nbytes = FDSETSIZE (max_fd_size);
120
121 nrset = alloca (nbytes);
122 nwset = alloca (nbytes);
123 nxset = alloca (nbytes);
124
125 memset ((char *) nrset + bytes, 0, nbytes - bytes);
126 memset ((char *) nwset + bytes, 0, nbytes - bytes);
127 memset ((char *) nxset + bytes, 0, nbytes - bytes);
128
129 rset = memcpy (nrset, rset, bytes);
130 wset = memcpy (nwset, wset, bytes);
131 xset = memcpy (nxset, xset, bytes);
132
133 bytes = nbytes;
134 }
135 #else
136 if (f->fd >= FD_SETSIZE) {
137 errno = EBADF;
138 return -1;
139 }
140 #endif /* HAVE_ALLOCA_H */
141
142 if (f->events & POLLIN)
143 FD_SET (f->fd, rset);
144 if (f->events & POLLOUT)
145 FD_SET (f->fd, wset);
146 if (f->events & POLLPRI)
147 FD_SET (f->fd, xset);
148 if (f->fd > maxfd && (f->events & (POLLIN|POLLOUT|POLLPRI)))
149 maxfd = f->fd;
150 }
151 }
152
153 tv.tv_sec = timeout / 1000;
154 tv.tv_usec = (timeout % 1000) * 1000;
155
156 while (1)
157 {
158 ready = select (maxfd + 1, rset, wset, xset,
159 timeout == -1 ? NULL : &tv);
160
161 /* It might be that one or more of the file descriptors is invalid.
162 We now try to find and mark them and then try again. */
163 if (ready == -1 && errno == EBADF)
164 {
165 struct timeval sngl_tv;
166 #if HAVE_ALLOCA_H
167 fd_set *sngl_rset = alloca (bytes);
168 fd_set *sngl_wset = alloca (bytes);
169 fd_set *sngl_xset = alloca (bytes);
170
171 /* Clear the original set. */
172 memset (rset, 0, bytes);
173 memset (wset, 0, bytes);
174 memset (xset, 0, bytes);
175 #else
176 fd_set sngl_rset[1];
177 fd_set sngl_wset[1];
178 fd_set sngl_xset[1];
179
180 FD_ZERO(rset);
181 FD_ZERO(wset);
182 FD_ZERO(xset);
183 #endif
184
185 /* This means we don't wait for input. */
186 sngl_tv.tv_sec = 0;
187 sngl_tv.tv_usec = 0;
188
189 maxfd = -1;
190
191 /* Reset the return value. */
192 ready = 0;
193
194 for (f = fds; f < &fds[nfds]; ++f)
195 if (f->fd != -1 && (f->events & (POLLIN|POLLOUT|POLLPRI))
196 && (f->revents & POLLNVAL) == 0)
197 {
198 int n;
199
200 #if HAVE_ALLOCA_H
201 memset (sngl_rset, 0, bytes);
202 memset (sngl_wset, 0, bytes);
203 memset (sngl_xset, 0, bytes);
204 #else
205 FD_ZERO(rset);
206 FD_ZERO(wset);
207 FD_ZERO(xset);
208 #endif
209
210 if (f->events & POLLIN)
211 FD_SET (f->fd, sngl_rset);
212 if (f->events & POLLOUT)
213 FD_SET (f->fd, sngl_wset);
214 if (f->events & POLLPRI)
215 FD_SET (f->fd, sngl_xset);
216
217 n = select (f->fd + 1, sngl_rset, sngl_wset, sngl_xset,
218 &sngl_tv);
219 if (n != -1)
220 {
221 /* This descriptor is ok. */
222 if (f->events & POLLIN)
223 FD_SET (f->fd, rset);
224 if (f->events & POLLOUT)
225 FD_SET (f->fd, wset);
226 if (f->events & POLLPRI)
227 FD_SET (f->fd, xset);
228 if (f->fd > maxfd)
229 maxfd = f->fd;
230 if (n > 0)
231 /* Count it as being available. */
232 ++ready;
233 }
234 else if (errno == EBADF)
235 f->revents |= POLLNVAL;
236 }
237 /* Try again. */
238 continue;
239 }
240
241 break;
242 }
243
244 if (ready > 0)
245 for (f = fds; f < &fds[nfds]; ++f)
246 {
247 if (f->fd >= 0)
248 {
249 if (FD_ISSET (f->fd, rset))
250 f->revents |= POLLIN;
251 if (FD_ISSET (f->fd, wset))
252 f->revents |= POLLOUT;
253 if (FD_ISSET (f->fd, xset))
254 f->revents |= POLLPRI;
255 }
256 }
257
258 return ready;
259 }
260
261 #endif
262