1 | /***************************************************************************
|
---|
2 | * _ _ ____ _
|
---|
3 | * Project ___| | | | _ \| |
|
---|
4 | * / __| | | | |_) | |
|
---|
5 | * | (__| |_| | _ <| |___
|
---|
6 | * \___|\___/|_| \_\_____|
|
---|
7 | *
|
---|
8 | * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
|
---|
9 | *
|
---|
10 | * This software is licensed as described in the file COPYING, which
|
---|
11 | * you should have received as part of this distribution. The terms
|
---|
12 | * are also available at https://curl.se/docs/copyright.html.
|
---|
13 | *
|
---|
14 | * You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
---|
15 | * copies of the Software, and permit persons to whom the Software is
|
---|
16 | * furnished to do so, under the terms of the COPYING file.
|
---|
17 | *
|
---|
18 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
---|
19 | * KIND, either express or implied.
|
---|
20 | *
|
---|
21 | * SPDX-License-Identifier: curl
|
---|
22 | *
|
---|
23 | ***************************************************************************/
|
---|
24 |
|
---|
25 | #include "curl_setup.h"
|
---|
26 |
|
---|
27 | #if !defined(HAVE_SELECT) && !defined(HAVE_POLL)
|
---|
28 | #error "We cannot compile without select() or poll() support."
|
---|
29 | #endif
|
---|
30 |
|
---|
31 | #include <limits.h>
|
---|
32 |
|
---|
33 | #ifdef HAVE_SYS_SELECT_H
|
---|
34 | #include <sys/select.h>
|
---|
35 | #elif defined(HAVE_UNISTD_H)
|
---|
36 | #include <unistd.h>
|
---|
37 | #endif
|
---|
38 |
|
---|
39 | #ifdef MSDOS
|
---|
40 | #include <dos.h> /* delay() */
|
---|
41 | #endif
|
---|
42 |
|
---|
43 | #include <curl/curl.h>
|
---|
44 |
|
---|
45 | #include "urldata.h"
|
---|
46 | #include "connect.h"
|
---|
47 | #include "select.h"
|
---|
48 | #include "timediff.h"
|
---|
49 | #include "warnless.h"
|
---|
50 | /* The last 3 #include files should be in this order */
|
---|
51 | #include "curl_printf.h"
|
---|
52 | #include "curl_memory.h"
|
---|
53 | #include "memdebug.h"
|
---|
54 |
|
---|
55 | /*
|
---|
56 | * Internal function used for waiting a specific amount of ms in
|
---|
57 | * Curl_socket_check() and Curl_poll() when no file descriptor is provided to
|
---|
58 | * wait on, just being used to delay execution. Winsock select() and poll()
|
---|
59 | * timeout mechanisms need a valid socket descriptor in a not null file
|
---|
60 | * descriptor set to work. Waiting indefinitely with this function is not
|
---|
61 | * allowed, a zero or negative timeout value will return immediately. Timeout
|
---|
62 | * resolution, accuracy, as well as maximum supported value is system
|
---|
63 | * dependent, neither factor is a critical issue for the intended use of this
|
---|
64 | * function in the library.
|
---|
65 | *
|
---|
66 | * Return values:
|
---|
67 | * -1 = system call error, or invalid timeout value
|
---|
68 | * 0 = specified timeout has elapsed, or interrupted
|
---|
69 | */
|
---|
70 | int Curl_wait_ms(timediff_t timeout_ms)
|
---|
71 | {
|
---|
72 | int r = 0;
|
---|
73 |
|
---|
74 | if(!timeout_ms)
|
---|
75 | return 0;
|
---|
76 | if(timeout_ms < 0) {
|
---|
77 | SET_SOCKERRNO(EINVAL);
|
---|
78 | return -1;
|
---|
79 | }
|
---|
80 | #if defined(MSDOS)
|
---|
81 | delay(timeout_ms);
|
---|
82 | #elif defined(_WIN32)
|
---|
83 | /* prevent overflow, timeout_ms is typecast to ULONG/DWORD. */
|
---|
84 | #if TIMEDIFF_T_MAX >= ULONG_MAX
|
---|
85 | if(timeout_ms >= ULONG_MAX)
|
---|
86 | timeout_ms = ULONG_MAX-1;
|
---|
87 | /* do not use ULONG_MAX, because that is equal to INFINITE */
|
---|
88 | #endif
|
---|
89 | Sleep((ULONG)timeout_ms);
|
---|
90 | #else
|
---|
91 | /* avoid using poll() for this since it behaves incorrectly with no sockets
|
---|
92 | on Apple operating systems */
|
---|
93 | {
|
---|
94 | struct timeval pending_tv;
|
---|
95 | r = select(0, NULL, NULL, NULL, curlx_mstotv(&pending_tv, timeout_ms));
|
---|
96 | }
|
---|
97 | #endif /* _WIN32 */
|
---|
98 | if(r) {
|
---|
99 | if((r == -1) && (SOCKERRNO == EINTR))
|
---|
100 | /* make EINTR from select or poll not a "lethal" error */
|
---|
101 | r = 0;
|
---|
102 | else
|
---|
103 | r = -1;
|
---|
104 | }
|
---|
105 | return r;
|
---|
106 | }
|
---|
107 |
|
---|
108 | #ifndef HAVE_POLL
|
---|
109 | /*
|
---|
110 | * This is a wrapper around select() to aid in Windows compatibility. A
|
---|
111 | * negative timeout value makes this function wait indefinitely, unless no
|
---|
112 | * valid file descriptor is given, when this happens the negative timeout is
|
---|
113 | * ignored and the function times out immediately.
|
---|
114 | *
|
---|
115 | * Return values:
|
---|
116 | * -1 = system call error or fd >= FD_SETSIZE
|
---|
117 | * 0 = timeout
|
---|
118 | * N = number of signalled file descriptors
|
---|
119 | */
|
---|
120 | static int our_select(curl_socket_t maxfd, /* highest socket number */
|
---|
121 | fd_set *fds_read, /* sockets ready for reading */
|
---|
122 | fd_set *fds_write, /* sockets ready for writing */
|
---|
123 | fd_set *fds_err, /* sockets with errors */
|
---|
124 | timediff_t timeout_ms) /* milliseconds to wait */
|
---|
125 | {
|
---|
126 | struct timeval pending_tv;
|
---|
127 | struct timeval *ptimeout;
|
---|
128 |
|
---|
129 | #ifdef USE_WINSOCK
|
---|
130 | /* Winsock select() cannot handle zero events. See the comment below. */
|
---|
131 | if((!fds_read || fds_read->fd_count == 0) &&
|
---|
132 | (!fds_write || fds_write->fd_count == 0) &&
|
---|
133 | (!fds_err || fds_err->fd_count == 0)) {
|
---|
134 | /* no sockets, just wait */
|
---|
135 | return Curl_wait_ms(timeout_ms);
|
---|
136 | }
|
---|
137 | #endif
|
---|
138 |
|
---|
139 | ptimeout = curlx_mstotv(&pending_tv, timeout_ms);
|
---|
140 |
|
---|
141 | #ifdef USE_WINSOCK
|
---|
142 | /* Winsock select() must not be called with an fd_set that contains zero
|
---|
143 | fd flags, or it will return WSAEINVAL. But, it also cannot be called
|
---|
144 | with no fd_sets at all! From the documentation:
|
---|
145 |
|
---|
146 | Any two of the parameters, readfds, writefds, or exceptfds, can be
|
---|
147 | given as null. At least one must be non-null, and any non-null
|
---|
148 | descriptor set must contain at least one handle to a socket.
|
---|
149 |
|
---|
150 | It is unclear why Winsock does not just handle this for us instead of
|
---|
151 | calling this an error. Luckily, with Winsock, we can _also_ ask how
|
---|
152 | many bits are set on an fd_set. So, let's just check it beforehand.
|
---|
153 | */
|
---|
154 | return select((int)maxfd + 1,
|
---|
155 | fds_read && fds_read->fd_count ? fds_read : NULL,
|
---|
156 | fds_write && fds_write->fd_count ? fds_write : NULL,
|
---|
157 | fds_err && fds_err->fd_count ? fds_err : NULL, ptimeout);
|
---|
158 | #else
|
---|
159 | return select((int)maxfd + 1, fds_read, fds_write, fds_err, ptimeout);
|
---|
160 | #endif
|
---|
161 | }
|
---|
162 |
|
---|
163 | #endif
|
---|
164 |
|
---|
165 | /*
|
---|
166 | * Wait for read or write events on a set of file descriptors. It uses poll()
|
---|
167 | * when poll() is available, in order to avoid limits with FD_SETSIZE,
|
---|
168 | * otherwise select() is used. An error is returned if select() is being used
|
---|
169 | * and a file descriptor is too large for FD_SETSIZE.
|
---|
170 | *
|
---|
171 | * A negative timeout value makes this function wait indefinitely, unless no
|
---|
172 | * valid file descriptor is given, when this happens the negative timeout is
|
---|
173 | * ignored and the function times out immediately.
|
---|
174 | *
|
---|
175 | * Return values:
|
---|
176 | * -1 = system call error or fd >= FD_SETSIZE
|
---|
177 | * 0 = timeout
|
---|
178 | * [bitmask] = action as described below
|
---|
179 | *
|
---|
180 | * CURL_CSELECT_IN - first socket is readable
|
---|
181 | * CURL_CSELECT_IN2 - second socket is readable
|
---|
182 | * CURL_CSELECT_OUT - write socket is writable
|
---|
183 | * CURL_CSELECT_ERR - an error condition occurred
|
---|
184 | */
|
---|
185 | int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */
|
---|
186 | curl_socket_t readfd1,
|
---|
187 | curl_socket_t writefd, /* socket to write to */
|
---|
188 | timediff_t timeout_ms) /* milliseconds to wait */
|
---|
189 | {
|
---|
190 | struct pollfd pfd[3];
|
---|
191 | int num;
|
---|
192 | int r;
|
---|
193 |
|
---|
194 | if((readfd0 == CURL_SOCKET_BAD) && (readfd1 == CURL_SOCKET_BAD) &&
|
---|
195 | (writefd == CURL_SOCKET_BAD)) {
|
---|
196 | /* no sockets, just wait */
|
---|
197 | return Curl_wait_ms(timeout_ms);
|
---|
198 | }
|
---|
199 |
|
---|
200 | /* Avoid initial timestamp, avoid Curl_now() call, when elapsed
|
---|
201 | time in this function does not need to be measured. This happens
|
---|
202 | when function is called with a zero timeout or a negative timeout
|
---|
203 | value indicating a blocking call should be performed. */
|
---|
204 |
|
---|
205 | num = 0;
|
---|
206 | if(readfd0 != CURL_SOCKET_BAD) {
|
---|
207 | pfd[num].fd = readfd0;
|
---|
208 | pfd[num].events = POLLRDNORM|POLLIN|POLLRDBAND|POLLPRI;
|
---|
209 | pfd[num].revents = 0;
|
---|
210 | num++;
|
---|
211 | }
|
---|
212 | if(readfd1 != CURL_SOCKET_BAD) {
|
---|
213 | pfd[num].fd = readfd1;
|
---|
214 | pfd[num].events = POLLRDNORM|POLLIN|POLLRDBAND|POLLPRI;
|
---|
215 | pfd[num].revents = 0;
|
---|
216 | num++;
|
---|
217 | }
|
---|
218 | if(writefd != CURL_SOCKET_BAD) {
|
---|
219 | pfd[num].fd = writefd;
|
---|
220 | pfd[num].events = POLLWRNORM|POLLOUT|POLLPRI;
|
---|
221 | pfd[num].revents = 0;
|
---|
222 | num++;
|
---|
223 | }
|
---|
224 |
|
---|
225 | r = Curl_poll(pfd, (unsigned int)num, timeout_ms);
|
---|
226 | if(r <= 0)
|
---|
227 | return r;
|
---|
228 |
|
---|
229 | r = 0;
|
---|
230 | num = 0;
|
---|
231 | if(readfd0 != CURL_SOCKET_BAD) {
|
---|
232 | if(pfd[num].revents & (POLLRDNORM|POLLIN|POLLERR|POLLHUP))
|
---|
233 | r |= CURL_CSELECT_IN;
|
---|
234 | if(pfd[num].revents & (POLLPRI|POLLNVAL))
|
---|
235 | r |= CURL_CSELECT_ERR;
|
---|
236 | num++;
|
---|
237 | }
|
---|
238 | if(readfd1 != CURL_SOCKET_BAD) {
|
---|
239 | if(pfd[num].revents & (POLLRDNORM|POLLIN|POLLERR|POLLHUP))
|
---|
240 | r |= CURL_CSELECT_IN2;
|
---|
241 | if(pfd[num].revents & (POLLPRI|POLLNVAL))
|
---|
242 | r |= CURL_CSELECT_ERR;
|
---|
243 | num++;
|
---|
244 | }
|
---|
245 | if(writefd != CURL_SOCKET_BAD) {
|
---|
246 | if(pfd[num].revents & (POLLWRNORM|POLLOUT))
|
---|
247 | r |= CURL_CSELECT_OUT;
|
---|
248 | if(pfd[num].revents & (POLLERR|POLLHUP|POLLPRI|POLLNVAL))
|
---|
249 | r |= CURL_CSELECT_ERR;
|
---|
250 | }
|
---|
251 |
|
---|
252 | return r;
|
---|
253 | }
|
---|
254 |
|
---|
255 | /*
|
---|
256 | * This is a wrapper around poll(). If poll() does not exist, then
|
---|
257 | * select() is used instead. An error is returned if select() is
|
---|
258 | * being used and a file descriptor is too large for FD_SETSIZE.
|
---|
259 | * A negative timeout value makes this function wait indefinitely,
|
---|
260 | * unless no valid file descriptor is given, when this happens the
|
---|
261 | * negative timeout is ignored and the function times out immediately.
|
---|
262 | *
|
---|
263 | * Return values:
|
---|
264 | * -1 = system call error or fd >= FD_SETSIZE
|
---|
265 | * 0 = timeout
|
---|
266 | * N = number of structures with non zero revent fields
|
---|
267 | */
|
---|
268 | int Curl_poll(struct pollfd ufds[], unsigned int nfds, timediff_t timeout_ms)
|
---|
269 | {
|
---|
270 | #ifdef HAVE_POLL
|
---|
271 | int pending_ms;
|
---|
272 | #else
|
---|
273 | fd_set fds_read;
|
---|
274 | fd_set fds_write;
|
---|
275 | fd_set fds_err;
|
---|
276 | curl_socket_t maxfd;
|
---|
277 | #endif
|
---|
278 | bool fds_none = TRUE;
|
---|
279 | unsigned int i;
|
---|
280 | int r;
|
---|
281 |
|
---|
282 | if(ufds) {
|
---|
283 | for(i = 0; i < nfds; i++) {
|
---|
284 | if(ufds[i].fd != CURL_SOCKET_BAD) {
|
---|
285 | fds_none = FALSE;
|
---|
286 | break;
|
---|
287 | }
|
---|
288 | }
|
---|
289 | }
|
---|
290 | if(fds_none) {
|
---|
291 | /* no sockets, just wait */
|
---|
292 | return Curl_wait_ms(timeout_ms);
|
---|
293 | }
|
---|
294 |
|
---|
295 | /* Avoid initial timestamp, avoid Curl_now() call, when elapsed
|
---|
296 | time in this function does not need to be measured. This happens
|
---|
297 | when function is called with a zero timeout or a negative timeout
|
---|
298 | value indicating a blocking call should be performed. */
|
---|
299 |
|
---|
300 | #ifdef HAVE_POLL
|
---|
301 |
|
---|
302 | /* prevent overflow, timeout_ms is typecast to int. */
|
---|
303 | #if TIMEDIFF_T_MAX > INT_MAX
|
---|
304 | if(timeout_ms > INT_MAX)
|
---|
305 | timeout_ms = INT_MAX;
|
---|
306 | #endif
|
---|
307 | if(timeout_ms > 0)
|
---|
308 | pending_ms = (int)timeout_ms;
|
---|
309 | else if(timeout_ms < 0)
|
---|
310 | pending_ms = -1;
|
---|
311 | else
|
---|
312 | pending_ms = 0;
|
---|
313 | r = poll(ufds, nfds, pending_ms);
|
---|
314 | if(r <= 0) {
|
---|
315 | if((r == -1) && (SOCKERRNO == EINTR))
|
---|
316 | /* make EINTR from select or poll not a "lethal" error */
|
---|
317 | r = 0;
|
---|
318 | return r;
|
---|
319 | }
|
---|
320 |
|
---|
321 | for(i = 0; i < nfds; i++) {
|
---|
322 | if(ufds[i].fd == CURL_SOCKET_BAD)
|
---|
323 | continue;
|
---|
324 | if(ufds[i].revents & POLLHUP)
|
---|
325 | ufds[i].revents |= POLLIN;
|
---|
326 | if(ufds[i].revents & POLLERR)
|
---|
327 | ufds[i].revents |= POLLIN|POLLOUT;
|
---|
328 | }
|
---|
329 |
|
---|
330 | #else /* HAVE_POLL */
|
---|
331 |
|
---|
332 | FD_ZERO(&fds_read);
|
---|
333 | FD_ZERO(&fds_write);
|
---|
334 | FD_ZERO(&fds_err);
|
---|
335 | maxfd = (curl_socket_t)-1;
|
---|
336 |
|
---|
337 | for(i = 0; i < nfds; i++) {
|
---|
338 | ufds[i].revents = 0;
|
---|
339 | if(ufds[i].fd == CURL_SOCKET_BAD)
|
---|
340 | continue;
|
---|
341 | VERIFY_SOCK(ufds[i].fd);
|
---|
342 | if(ufds[i].events & (POLLIN|POLLOUT|POLLPRI|
|
---|
343 | POLLRDNORM|POLLWRNORM|POLLRDBAND)) {
|
---|
344 | if(ufds[i].fd > maxfd)
|
---|
345 | maxfd = ufds[i].fd;
|
---|
346 | if(ufds[i].events & (POLLRDNORM|POLLIN))
|
---|
347 | FD_SET(ufds[i].fd, &fds_read);
|
---|
348 | if(ufds[i].events & (POLLWRNORM|POLLOUT))
|
---|
349 | FD_SET(ufds[i].fd, &fds_write);
|
---|
350 | if(ufds[i].events & (POLLRDBAND|POLLPRI))
|
---|
351 | FD_SET(ufds[i].fd, &fds_err);
|
---|
352 | }
|
---|
353 | }
|
---|
354 |
|
---|
355 | /*
|
---|
356 | Note also that Winsock ignores the first argument, so we do not worry
|
---|
357 | about the fact that maxfd is computed incorrectly with Winsock (since
|
---|
358 | curl_socket_t is unsigned in such cases and thus -1 is the largest
|
---|
359 | value).
|
---|
360 | */
|
---|
361 | r = our_select(maxfd, &fds_read, &fds_write, &fds_err, timeout_ms);
|
---|
362 | if(r <= 0) {
|
---|
363 | if((r == -1) && (SOCKERRNO == EINTR))
|
---|
364 | /* make EINTR from select or poll not a "lethal" error */
|
---|
365 | r = 0;
|
---|
366 | return r;
|
---|
367 | }
|
---|
368 |
|
---|
369 | r = 0;
|
---|
370 | for(i = 0; i < nfds; i++) {
|
---|
371 | ufds[i].revents = 0;
|
---|
372 | if(ufds[i].fd == CURL_SOCKET_BAD)
|
---|
373 | continue;
|
---|
374 | if(FD_ISSET(ufds[i].fd, &fds_read)) {
|
---|
375 | if(ufds[i].events & POLLRDNORM)
|
---|
376 | ufds[i].revents |= POLLRDNORM;
|
---|
377 | if(ufds[i].events & POLLIN)
|
---|
378 | ufds[i].revents |= POLLIN;
|
---|
379 | }
|
---|
380 | if(FD_ISSET(ufds[i].fd, &fds_write)) {
|
---|
381 | if(ufds[i].events & POLLWRNORM)
|
---|
382 | ufds[i].revents |= POLLWRNORM;
|
---|
383 | if(ufds[i].events & POLLOUT)
|
---|
384 | ufds[i].revents |= POLLOUT;
|
---|
385 | }
|
---|
386 | if(FD_ISSET(ufds[i].fd, &fds_err)) {
|
---|
387 | if(ufds[i].events & POLLRDBAND)
|
---|
388 | ufds[i].revents |= POLLRDBAND;
|
---|
389 | if(ufds[i].events & POLLPRI)
|
---|
390 | ufds[i].revents |= POLLPRI;
|
---|
391 | }
|
---|
392 | if(ufds[i].revents)
|
---|
393 | r++;
|
---|
394 | }
|
---|
395 |
|
---|
396 | #endif /* HAVE_POLL */
|
---|
397 |
|
---|
398 | return r;
|
---|
399 | }
|
---|
400 |
|
---|
401 | void Curl_pollfds_init(struct curl_pollfds *cpfds,
|
---|
402 | struct pollfd *static_pfds,
|
---|
403 | unsigned int static_count)
|
---|
404 | {
|
---|
405 | DEBUGASSERT(cpfds);
|
---|
406 | memset(cpfds, 0, sizeof(*cpfds));
|
---|
407 | if(static_pfds && static_count) {
|
---|
408 | cpfds->pfds = static_pfds;
|
---|
409 | cpfds->count = static_count;
|
---|
410 | }
|
---|
411 | }
|
---|
412 |
|
---|
413 | void Curl_pollfds_cleanup(struct curl_pollfds *cpfds)
|
---|
414 | {
|
---|
415 | DEBUGASSERT(cpfds);
|
---|
416 | if(cpfds->allocated_pfds) {
|
---|
417 | free(cpfds->pfds);
|
---|
418 | }
|
---|
419 | memset(cpfds, 0, sizeof(*cpfds));
|
---|
420 | }
|
---|
421 |
|
---|
422 | static CURLcode cpfds_increase(struct curl_pollfds *cpfds, unsigned int inc)
|
---|
423 | {
|
---|
424 | struct pollfd *new_fds;
|
---|
425 | unsigned int new_count = cpfds->count + inc;
|
---|
426 |
|
---|
427 | new_fds = calloc(new_count, sizeof(struct pollfd));
|
---|
428 | if(!new_fds)
|
---|
429 | return CURLE_OUT_OF_MEMORY;
|
---|
430 |
|
---|
431 | memcpy(new_fds, cpfds->pfds, cpfds->count * sizeof(struct pollfd));
|
---|
432 | if(cpfds->allocated_pfds)
|
---|
433 | free(cpfds->pfds);
|
---|
434 | cpfds->pfds = new_fds;
|
---|
435 | cpfds->count = new_count;
|
---|
436 | cpfds->allocated_pfds = TRUE;
|
---|
437 | return CURLE_OK;
|
---|
438 | }
|
---|
439 |
|
---|
440 | static CURLcode cpfds_add_sock(struct curl_pollfds *cpfds,
|
---|
441 | curl_socket_t sock, short events, bool fold)
|
---|
442 | {
|
---|
443 | int i;
|
---|
444 |
|
---|
445 | if(fold && cpfds->n <= INT_MAX) {
|
---|
446 | for(i = (int)cpfds->n - 1; i >= 0; --i) {
|
---|
447 | if(sock == cpfds->pfds[i].fd) {
|
---|
448 | cpfds->pfds[i].events |= events;
|
---|
449 | return CURLE_OK;
|
---|
450 | }
|
---|
451 | }
|
---|
452 | }
|
---|
453 | /* not folded, add new entry */
|
---|
454 | if(cpfds->n >= cpfds->count) {
|
---|
455 | if(cpfds_increase(cpfds, 100))
|
---|
456 | return CURLE_OUT_OF_MEMORY;
|
---|
457 | }
|
---|
458 | cpfds->pfds[cpfds->n].fd = sock;
|
---|
459 | cpfds->pfds[cpfds->n].events = events;
|
---|
460 | ++cpfds->n;
|
---|
461 | return CURLE_OK;
|
---|
462 | }
|
---|
463 |
|
---|
464 | CURLcode Curl_pollfds_add_sock(struct curl_pollfds *cpfds,
|
---|
465 | curl_socket_t sock, short events)
|
---|
466 | {
|
---|
467 | return cpfds_add_sock(cpfds, sock, events, FALSE);
|
---|
468 | }
|
---|
469 |
|
---|
470 | CURLcode Curl_pollfds_add_ps(struct curl_pollfds *cpfds,
|
---|
471 | struct easy_pollset *ps)
|
---|
472 | {
|
---|
473 | size_t i;
|
---|
474 |
|
---|
475 | DEBUGASSERT(cpfds);
|
---|
476 | DEBUGASSERT(ps);
|
---|
477 | for(i = 0; i < ps->num; i++) {
|
---|
478 | short events = 0;
|
---|
479 | if(ps->actions[i] & CURL_POLL_IN)
|
---|
480 | events |= POLLIN;
|
---|
481 | if(ps->actions[i] & CURL_POLL_OUT)
|
---|
482 | events |= POLLOUT;
|
---|
483 | if(events) {
|
---|
484 | if(cpfds_add_sock(cpfds, ps->sockets[i], events, TRUE))
|
---|
485 | return CURLE_OUT_OF_MEMORY;
|
---|
486 | }
|
---|
487 | }
|
---|
488 | return CURLE_OK;
|
---|
489 | }
|
---|
490 |
|
---|
491 | void Curl_waitfds_init(struct curl_waitfds *cwfds,
|
---|
492 | struct curl_waitfd *static_wfds,
|
---|
493 | unsigned int static_count)
|
---|
494 | {
|
---|
495 | DEBUGASSERT(cwfds);
|
---|
496 | DEBUGASSERT(static_wfds);
|
---|
497 | memset(cwfds, 0, sizeof(*cwfds));
|
---|
498 | cwfds->wfds = static_wfds;
|
---|
499 | cwfds->count = static_count;
|
---|
500 | }
|
---|
501 |
|
---|
502 | static CURLcode cwfds_add_sock(struct curl_waitfds *cwfds,
|
---|
503 | curl_socket_t sock, short events)
|
---|
504 | {
|
---|
505 | int i;
|
---|
506 |
|
---|
507 | if(cwfds->n <= INT_MAX) {
|
---|
508 | for(i = (int)cwfds->n - 1; i >= 0; --i) {
|
---|
509 | if(sock == cwfds->wfds[i].fd) {
|
---|
510 | cwfds->wfds[i].events |= events;
|
---|
511 | return CURLE_OK;
|
---|
512 | }
|
---|
513 | }
|
---|
514 | }
|
---|
515 | /* not folded, add new entry */
|
---|
516 | if(cwfds->n >= cwfds->count)
|
---|
517 | return CURLE_OUT_OF_MEMORY;
|
---|
518 | cwfds->wfds[cwfds->n].fd = sock;
|
---|
519 | cwfds->wfds[cwfds->n].events = events;
|
---|
520 | ++cwfds->n;
|
---|
521 | return CURLE_OK;
|
---|
522 | }
|
---|
523 |
|
---|
524 | CURLcode Curl_waitfds_add_ps(struct curl_waitfds *cwfds,
|
---|
525 | struct easy_pollset *ps)
|
---|
526 | {
|
---|
527 | size_t i;
|
---|
528 |
|
---|
529 | DEBUGASSERT(cwfds);
|
---|
530 | DEBUGASSERT(ps);
|
---|
531 | for(i = 0; i < ps->num; i++) {
|
---|
532 | short events = 0;
|
---|
533 | if(ps->actions[i] & CURL_POLL_IN)
|
---|
534 | events |= CURL_WAIT_POLLIN;
|
---|
535 | if(ps->actions[i] & CURL_POLL_OUT)
|
---|
536 | events |= CURL_WAIT_POLLOUT;
|
---|
537 | if(events) {
|
---|
538 | if(cwfds_add_sock(cwfds, ps->sockets[i], events))
|
---|
539 | return CURLE_OUT_OF_MEMORY;
|
---|
540 | }
|
---|
541 | }
|
---|
542 | return CURLE_OK;
|
---|
543 | }
|
---|