Line | Count | Source |
1 | | /*************************************************************************** |
2 | | * _ _ ____ _ |
3 | | * Project ___| | | | _ \| | |
4 | | * / __| | | | |_) | | |
5 | | * | (__| |_| | _ <| |___ |
6 | | * \___|\___/|_| \_\_____| |
7 | | * |
8 | | * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, 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 | | #include "curl_setup.h" |
25 | | |
26 | | #ifdef HAVE_SYS_SELECT_H |
27 | | #include <sys/select.h> |
28 | | #elif defined(HAVE_UNISTD_H) |
29 | | #include <unistd.h> |
30 | | #endif |
31 | | |
32 | | #include "urldata.h" |
33 | | #include "connect.h" |
34 | | #include "select.h" |
35 | | #include "curl_trc.h" |
36 | | #include "curlx/timediff.h" |
37 | | #include "curlx/wait.h" |
38 | | |
39 | | #ifndef HAVE_POLL /* use select() */ |
40 | | /* |
41 | | * This is a wrapper around select() to aid in Windows compatibility. A |
42 | | * negative timeout value makes this function wait indefinitely, unless no |
43 | | * valid file descriptor is given, when this happens the negative timeout is |
44 | | * ignored and the function times out immediately. |
45 | | * |
46 | | * Return values: |
47 | | * -1 = system call error or fd >= FD_SETSIZE |
48 | | * 0 = timeout |
49 | | * N = number of signalled file descriptors |
50 | | */ |
51 | | static int our_select(curl_socket_t maxfd, /* highest socket number */ |
52 | | fd_set *fds_read, /* sockets ready for reading */ |
53 | | fd_set *fds_write, /* sockets ready for writing */ |
54 | | fd_set *fds_err, /* sockets with errors */ |
55 | | timediff_t timeout_ms) /* milliseconds to wait */ |
56 | | { |
57 | | struct timeval pending_tv; |
58 | | struct timeval *ptimeout; |
59 | | |
60 | | #ifdef USE_WINSOCK |
61 | | /* Winsock select() cannot handle zero events. See the comment below. */ |
62 | | if((!fds_read || fds_read->fd_count == 0) && |
63 | | (!fds_write || fds_write->fd_count == 0) && |
64 | | (!fds_err || fds_err->fd_count == 0)) { |
65 | | /* no sockets, wait */ |
66 | | return curlx_wait_ms(timeout_ms); |
67 | | } |
68 | | #endif |
69 | | |
70 | | ptimeout = curlx_mstotv(&pending_tv, timeout_ms); |
71 | | |
72 | | #ifdef USE_WINSOCK |
73 | | /* Winsock select() must not be called with an fd_set that contains zero |
74 | | fd flags, or it will return WSAEINVAL. It also cannot be called with |
75 | | no fd_sets at all! From the documentation: |
76 | | |
77 | | Any two of the parameters, readfds, writefds, or exceptfds, can be |
78 | | given as null. At least one must be non-null, and any non-null |
79 | | descriptor set must contain at least one handle to a socket. |
80 | | |
81 | | It is unclear why Winsock does not handle this for us instead of |
82 | | calling this an error. Luckily, with Winsock, we can _also_ ask how |
83 | | many bits are set on an fd_set. Therefore, let's check it beforehand. |
84 | | */ |
85 | | return select((int)maxfd + 1, |
86 | | fds_read && fds_read->fd_count ? fds_read : NULL, |
87 | | fds_write && fds_write->fd_count ? fds_write : NULL, |
88 | | fds_err && fds_err->fd_count ? fds_err : NULL, ptimeout); |
89 | | #else |
90 | | return select((int)maxfd + 1, fds_read, fds_write, fds_err, ptimeout); |
91 | | #endif |
92 | | } |
93 | | |
94 | | #endif |
95 | | |
96 | | /* |
97 | | * Wait for read or write events on a set of file descriptors. It uses poll() |
98 | | * when poll() is available, in order to avoid limits with FD_SETSIZE, |
99 | | * otherwise select() is used. An error is returned if select() is being used |
100 | | * and a file descriptor is too large for FD_SETSIZE. |
101 | | * |
102 | | * A negative timeout value makes this function wait indefinitely, unless no |
103 | | * valid file descriptor is given, when this happens the negative timeout is |
104 | | * ignored and the function times out immediately. |
105 | | * |
106 | | * Return values: |
107 | | * -1 = system call error or fd >= FD_SETSIZE |
108 | | * 0 = timeout |
109 | | * [bitmask] = action as described below |
110 | | * |
111 | | * CURL_CSELECT_IN - first socket is readable |
112 | | * CURL_CSELECT_IN2 - second socket is readable |
113 | | * CURL_CSELECT_OUT - write socket is writable |
114 | | * CURL_CSELECT_ERR - an error condition occurred |
115 | | */ |
116 | | int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */ |
117 | | curl_socket_t readfd1, |
118 | | curl_socket_t writefd, /* socket to write to */ |
119 | | timediff_t timeout_ms) /* milliseconds to wait */ |
120 | 31 | { |
121 | 31 | struct pollfd pfd[3]; |
122 | 31 | int num; |
123 | 31 | int r; |
124 | | |
125 | 31 | if((readfd0 == CURL_SOCKET_BAD) && (readfd1 == CURL_SOCKET_BAD) && |
126 | 31 | (writefd == CURL_SOCKET_BAD)) { |
127 | | /* no sockets, wait */ |
128 | 0 | return curlx_wait_ms(timeout_ms); |
129 | 0 | } |
130 | | |
131 | | /* Avoid initial timestamp, avoid curlx_now() call, when elapsed |
132 | | time in this function does not need to be measured. This happens |
133 | | when function is called with a zero timeout or a negative timeout |
134 | | value indicating a blocking call should be performed. */ |
135 | | |
136 | 31 | num = 0; |
137 | 31 | if(readfd0 != CURL_SOCKET_BAD) { |
138 | 0 | pfd[num].fd = readfd0; |
139 | 0 | pfd[num].events = POLLRDNORM | POLLIN | POLLRDBAND | POLLPRI; |
140 | 0 | pfd[num].revents = 0; |
141 | 0 | num++; |
142 | 0 | } |
143 | 31 | if(readfd1 != CURL_SOCKET_BAD) { |
144 | 0 | pfd[num].fd = readfd1; |
145 | 0 | pfd[num].events = POLLRDNORM | POLLIN | POLLRDBAND | POLLPRI; |
146 | 0 | pfd[num].revents = 0; |
147 | 0 | num++; |
148 | 0 | } |
149 | 31 | if(writefd != CURL_SOCKET_BAD) { |
150 | 31 | pfd[num].fd = writefd; |
151 | 31 | pfd[num].events = POLLWRNORM | POLLOUT | POLLPRI; |
152 | 31 | pfd[num].revents = 0; |
153 | 31 | num++; |
154 | 31 | } |
155 | | |
156 | 31 | r = Curl_poll(pfd, (unsigned int)num, timeout_ms); |
157 | 31 | if(r <= 0) |
158 | 31 | return r; |
159 | | |
160 | 0 | r = 0; |
161 | 0 | num = 0; |
162 | 0 | if(readfd0 != CURL_SOCKET_BAD) { |
163 | 0 | if(pfd[num].revents & (POLLRDNORM | POLLIN | POLLERR | POLLHUP)) |
164 | 0 | r |= CURL_CSELECT_IN; |
165 | 0 | if(pfd[num].revents & (POLLPRI | POLLNVAL)) |
166 | 0 | r |= CURL_CSELECT_ERR; |
167 | 0 | num++; |
168 | 0 | } |
169 | 0 | if(readfd1 != CURL_SOCKET_BAD) { |
170 | 0 | if(pfd[num].revents & (POLLRDNORM | POLLIN | POLLERR | POLLHUP)) |
171 | 0 | r |= CURL_CSELECT_IN2; |
172 | 0 | if(pfd[num].revents & (POLLPRI | POLLNVAL)) |
173 | 0 | r |= CURL_CSELECT_ERR; |
174 | 0 | num++; |
175 | 0 | } |
176 | 0 | if(writefd != CURL_SOCKET_BAD) { |
177 | 0 | if(pfd[num].revents & (POLLWRNORM | POLLOUT)) |
178 | 0 | r |= CURL_CSELECT_OUT; |
179 | 0 | if(pfd[num].revents & (POLLERR | POLLHUP | POLLPRI | POLLNVAL)) |
180 | 0 | r |= CURL_CSELECT_ERR; |
181 | 0 | } |
182 | |
|
183 | 0 | return r; |
184 | 31 | } |
185 | | |
186 | | /* |
187 | | * This is a wrapper around poll(). If poll() does not exist, then |
188 | | * select() is used instead. An error is returned if select() is |
189 | | * being used and a file descriptor is too large for FD_SETSIZE. |
190 | | * A negative timeout value makes this function wait indefinitely, |
191 | | * unless no valid file descriptor is given, when this happens the |
192 | | * negative timeout is ignored and the function times out immediately. |
193 | | * |
194 | | * Return values: |
195 | | * -1 = system call error or fd >= FD_SETSIZE |
196 | | * 0 = timeout |
197 | | * N = number of structures with non zero revent fields |
198 | | */ |
199 | | int Curl_poll(struct pollfd ufds[], unsigned int nfds, timediff_t timeout_ms) |
200 | 31 | { |
201 | 31 | #ifdef HAVE_POLL |
202 | 31 | int pending_ms; |
203 | | #else |
204 | | fd_set fds_read; |
205 | | fd_set fds_write; |
206 | | fd_set fds_err; |
207 | | curl_socket_t maxfd; |
208 | | #endif |
209 | 31 | bool fds_none = TRUE; |
210 | 31 | unsigned int i; |
211 | 31 | int r; |
212 | | |
213 | 31 | if(ufds) { |
214 | 31 | for(i = 0; i < nfds; i++) { |
215 | 31 | if(ufds[i].fd != CURL_SOCKET_BAD) { |
216 | 31 | fds_none = FALSE; |
217 | 31 | break; |
218 | 31 | } |
219 | 31 | } |
220 | 31 | } |
221 | 31 | if(fds_none) { |
222 | | /* no sockets, wait */ |
223 | 0 | return curlx_wait_ms(timeout_ms); |
224 | 0 | } |
225 | | |
226 | | /* Avoid initial timestamp, avoid curlx_now() call, when elapsed |
227 | | time in this function does not need to be measured. This happens |
228 | | when function is called with a zero timeout or a negative timeout |
229 | | value indicating a blocking call should be performed. */ |
230 | | |
231 | 31 | #ifdef HAVE_POLL |
232 | | |
233 | | /* prevent overflow, timeout_ms is typecast to int. */ |
234 | 31 | #if TIMEDIFF_T_MAX > INT_MAX |
235 | 31 | if(timeout_ms > INT_MAX) |
236 | 7 | timeout_ms = INT_MAX; |
237 | 31 | #endif |
238 | 31 | if(timeout_ms > 0) |
239 | 31 | pending_ms = (int)timeout_ms; |
240 | 0 | else if(timeout_ms < 0) |
241 | 0 | pending_ms = -1; |
242 | 0 | else |
243 | 0 | pending_ms = 0; |
244 | 31 | r = poll(ufds, nfds, pending_ms); |
245 | 31 | if(r <= 0) { |
246 | 31 | if((r == -1) && (SOCKERRNO == SOCKEINTR)) |
247 | | /* make EINTR from select or poll not a "lethal" error */ |
248 | 7 | r = 0; |
249 | 31 | return r; |
250 | 31 | } |
251 | | |
252 | 0 | for(i = 0; i < nfds; i++) { |
253 | 0 | if(ufds[i].fd == CURL_SOCKET_BAD) |
254 | 0 | continue; |
255 | 0 | if(ufds[i].revents & POLLHUP) |
256 | 0 | ufds[i].revents |= POLLIN; |
257 | 0 | if(ufds[i].revents & POLLERR) |
258 | 0 | ufds[i].revents |= POLLIN | POLLOUT; |
259 | 0 | } |
260 | |
|
261 | | #else /* !HAVE_POLL */ |
262 | | |
263 | | FD_ZERO(&fds_read); |
264 | | FD_ZERO(&fds_write); |
265 | | FD_ZERO(&fds_err); |
266 | | maxfd = (curl_socket_t)-1; |
267 | | |
268 | | for(i = 0; i < nfds; i++) { |
269 | | ufds[i].revents = 0; |
270 | | if(ufds[i].fd == CURL_SOCKET_BAD) |
271 | | continue; |
272 | | VERIFY_SOCK(ufds[i].fd); |
273 | | if(ufds[i].events & (POLLIN | POLLOUT | POLLPRI | |
274 | | POLLRDNORM | POLLWRNORM | POLLRDBAND)) { |
275 | | if(ufds[i].fd > maxfd) |
276 | | maxfd = ufds[i].fd; |
277 | | if(ufds[i].events & (POLLRDNORM | POLLIN)) |
278 | | FD_SET(ufds[i].fd, &fds_read); |
279 | | if(ufds[i].events & (POLLWRNORM | POLLOUT)) |
280 | | FD_SET(ufds[i].fd, &fds_write); |
281 | | if(ufds[i].events & (POLLRDBAND | POLLPRI)) |
282 | | FD_SET(ufds[i].fd, &fds_err); |
283 | | } |
284 | | } |
285 | | |
286 | | /* Note also that Winsock ignores the first argument, so we do not worry |
287 | | about the fact that maxfd is computed incorrectly with Winsock (since |
288 | | curl_socket_t is unsigned in such cases and thus -1 is the largest |
289 | | value). */ |
290 | | r = our_select(maxfd, &fds_read, &fds_write, &fds_err, timeout_ms); |
291 | | if(r <= 0) { |
292 | | if((r == -1) && (SOCKERRNO == SOCKEINTR)) |
293 | | /* make EINTR from select or poll not a "lethal" error */ |
294 | | r = 0; |
295 | | return r; |
296 | | } |
297 | | |
298 | | r = 0; |
299 | | for(i = 0; i < nfds; i++) { |
300 | | ufds[i].revents = 0; |
301 | | if(ufds[i].fd == CURL_SOCKET_BAD) |
302 | | continue; |
303 | | if(FD_ISSET(ufds[i].fd, &fds_read)) { |
304 | | if(ufds[i].events & POLLRDNORM) |
305 | | ufds[i].revents |= POLLRDNORM; |
306 | | if(ufds[i].events & POLLIN) |
307 | | ufds[i].revents |= POLLIN; |
308 | | } |
309 | | if(FD_ISSET(ufds[i].fd, &fds_write)) { |
310 | | if(ufds[i].events & POLLWRNORM) |
311 | | ufds[i].revents |= POLLWRNORM; |
312 | | if(ufds[i].events & POLLOUT) |
313 | | ufds[i].revents |= POLLOUT; |
314 | | } |
315 | | if(FD_ISSET(ufds[i].fd, &fds_err)) { |
316 | | if(ufds[i].events & POLLRDBAND) |
317 | | ufds[i].revents |= POLLRDBAND; |
318 | | if(ufds[i].events & POLLPRI) |
319 | | ufds[i].revents |= POLLPRI; |
320 | | } |
321 | | if(ufds[i].revents) |
322 | | r++; |
323 | | } |
324 | | |
325 | | #endif /* HAVE_POLL */ |
326 | |
|
327 | 0 | return r; |
328 | 31 | } |
329 | | |
330 | | void Curl_pollfds_init(struct curl_pollfds *cpfds, |
331 | | struct pollfd *static_pfds, |
332 | | unsigned int static_count) |
333 | 4.63k | { |
334 | 4.63k | DEBUGASSERT(cpfds); |
335 | 4.63k | memset(cpfds, 0, sizeof(*cpfds)); |
336 | 4.63k | if(static_pfds && static_count) { |
337 | 4.63k | cpfds->pfds = static_pfds; |
338 | 4.63k | cpfds->count = static_count; |
339 | 4.63k | } |
340 | 4.63k | } |
341 | | |
342 | | void Curl_pollfds_reset(struct curl_pollfds *cpfds) |
343 | 0 | { |
344 | 0 | cpfds->n = 0; |
345 | 0 | } |
346 | | |
347 | | void Curl_pollfds_cleanup(struct curl_pollfds *cpfds) |
348 | 4.63k | { |
349 | 4.63k | DEBUGASSERT(cpfds); |
350 | 4.63k | if(cpfds->allocated_pfds) { |
351 | 0 | curlx_free(cpfds->pfds); |
352 | 0 | } |
353 | 4.63k | memset(cpfds, 0, sizeof(*cpfds)); |
354 | 4.63k | } |
355 | | |
356 | | static CURLcode cpfds_increase(struct curl_pollfds *cpfds, unsigned int inc) |
357 | 0 | { |
358 | 0 | struct pollfd *new_fds; |
359 | 0 | unsigned int new_count = cpfds->count + inc; |
360 | |
|
361 | 0 | new_fds = curlx_calloc(new_count, sizeof(struct pollfd)); |
362 | 0 | if(!new_fds) |
363 | 0 | return CURLE_OUT_OF_MEMORY; |
364 | | |
365 | 0 | memcpy(new_fds, cpfds->pfds, cpfds->count * sizeof(struct pollfd)); |
366 | 0 | if(cpfds->allocated_pfds) |
367 | 0 | curlx_free(cpfds->pfds); |
368 | 0 | cpfds->pfds = new_fds; |
369 | 0 | cpfds->count = new_count; |
370 | 0 | cpfds->allocated_pfds = TRUE; |
371 | 0 | return CURLE_OK; |
372 | 0 | } |
373 | | |
374 | | static CURLcode cpfds_add_sock(struct curl_pollfds *cpfds, |
375 | | curl_socket_t sock, short events, bool fold) |
376 | 0 | { |
377 | 0 | int i; |
378 | |
|
379 | 0 | if(fold && cpfds->n <= INT_MAX) { |
380 | 0 | for(i = (int)cpfds->n - 1; i >= 0; --i) { |
381 | 0 | if(sock == cpfds->pfds[i].fd) { |
382 | 0 | cpfds->pfds[i].events |= events; |
383 | 0 | return CURLE_OK; |
384 | 0 | } |
385 | 0 | } |
386 | 0 | } |
387 | | /* not folded, add new entry */ |
388 | 0 | if(cpfds->n >= cpfds->count && cpfds_increase(cpfds, 100)) |
389 | 0 | return CURLE_OUT_OF_MEMORY; |
390 | 0 | cpfds->pfds[cpfds->n].fd = sock; |
391 | 0 | cpfds->pfds[cpfds->n].events = events; |
392 | 0 | ++cpfds->n; |
393 | 0 | return CURLE_OK; |
394 | 0 | } |
395 | | |
396 | | CURLcode Curl_pollfds_add_sock(struct curl_pollfds *cpfds, |
397 | | curl_socket_t sock, short events) |
398 | 0 | { |
399 | 0 | return cpfds_add_sock(cpfds, sock, events, FALSE); |
400 | 0 | } |
401 | | |
402 | | CURLcode Curl_pollfds_add_ps(struct curl_pollfds *cpfds, |
403 | | struct easy_pollset *ps) |
404 | 0 | { |
405 | 0 | size_t i; |
406 | |
|
407 | 0 | DEBUGASSERT(cpfds); |
408 | 0 | DEBUGASSERT(ps); |
409 | 0 | for(i = 0; i < ps->n; i++) { |
410 | 0 | short events = 0; |
411 | 0 | if(ps->actions[i] & CURL_POLL_IN) |
412 | 0 | events |= POLLIN; |
413 | 0 | if(ps->actions[i] & CURL_POLL_OUT) |
414 | 0 | events |= POLLOUT; |
415 | 0 | if(events && cpfds_add_sock(cpfds, ps->sockets[i], events, TRUE)) |
416 | 0 | return CURLE_OUT_OF_MEMORY; |
417 | 0 | } |
418 | 0 | return CURLE_OK; |
419 | 0 | } |
420 | | |
421 | | void Curl_waitfds_init(struct Curl_waitfds *cwfds, |
422 | | struct curl_waitfd *static_wfds, |
423 | | unsigned int static_count) |
424 | 0 | { |
425 | 0 | DEBUGASSERT(cwfds); |
426 | 0 | DEBUGASSERT(static_wfds || !static_count); |
427 | 0 | memset(cwfds, 0, sizeof(*cwfds)); |
428 | 0 | cwfds->wfds = static_wfds; |
429 | 0 | cwfds->count = static_count; |
430 | 0 | } |
431 | | |
432 | | static unsigned int cwfds_add_sock(struct Curl_waitfds *cwfds, |
433 | | curl_socket_t sock, short events) |
434 | 0 | { |
435 | 0 | int i; |
436 | 0 | if(!cwfds->wfds) { |
437 | 0 | DEBUGASSERT(!cwfds->count && !cwfds->n); |
438 | 0 | return 1; |
439 | 0 | } |
440 | 0 | if(cwfds->n <= INT_MAX) { |
441 | 0 | for(i = (int)cwfds->n - 1; i >= 0; --i) { |
442 | 0 | if(sock == cwfds->wfds[i].fd) { |
443 | 0 | cwfds->wfds[i].events |= events; |
444 | 0 | return 0; |
445 | 0 | } |
446 | 0 | } |
447 | 0 | } |
448 | | /* not folded, add new entry */ |
449 | 0 | if(cwfds->n < cwfds->count) { |
450 | 0 | cwfds->wfds[cwfds->n].fd = sock; |
451 | 0 | cwfds->wfds[cwfds->n].events = events; |
452 | 0 | ++cwfds->n; |
453 | 0 | } |
454 | 0 | return 1; |
455 | 0 | } |
456 | | |
457 | | unsigned int Curl_waitfds_add_ps(struct Curl_waitfds *cwfds, |
458 | | struct easy_pollset *ps) |
459 | 0 | { |
460 | 0 | size_t i; |
461 | 0 | unsigned int need = 0; |
462 | |
|
463 | 0 | DEBUGASSERT(cwfds); |
464 | 0 | DEBUGASSERT(ps); |
465 | 0 | for(i = 0; i < ps->n; i++) { |
466 | 0 | short events = 0; |
467 | 0 | if(ps->actions[i] & CURL_POLL_IN) |
468 | 0 | events |= CURL_WAIT_POLLIN; |
469 | 0 | if(ps->actions[i] & CURL_POLL_OUT) |
470 | 0 | events |= CURL_WAIT_POLLOUT; |
471 | 0 | if(events) |
472 | 0 | need += cwfds_add_sock(cwfds, ps->sockets[i], events); |
473 | 0 | } |
474 | 0 | return need; |
475 | 0 | } |
476 | | |
477 | | void Curl_pollset_reset(struct easy_pollset *ps) |
478 | 13.8k | { |
479 | 13.8k | unsigned int i; |
480 | 13.8k | ps->n = 0; |
481 | 13.8k | #ifdef DEBUGBUILD |
482 | 13.8k | DEBUGASSERT(ps->init == CURL_EASY_POLLSET_MAGIC); |
483 | 13.8k | #endif |
484 | 13.8k | DEBUGASSERT(ps->count); |
485 | 41.6k | for(i = 0; i < ps->count; i++) |
486 | 27.7k | ps->sockets[i] = CURL_SOCKET_BAD; |
487 | 13.8k | memset(ps->actions, 0, ps->count * sizeof(ps->actions[0])); |
488 | 13.8k | } |
489 | | |
490 | | void Curl_pollset_init(struct easy_pollset *ps) |
491 | 5.78k | { |
492 | 5.78k | #ifdef DEBUGBUILD |
493 | 5.78k | ps->init = CURL_EASY_POLLSET_MAGIC; |
494 | 5.78k | #endif |
495 | 5.78k | ps->sockets = ps->def_sockets; |
496 | 5.78k | ps->actions = ps->def_actions; |
497 | 5.78k | ps->count = CURL_ARRAYSIZE(ps->def_sockets); |
498 | 5.78k | ps->n = 0; |
499 | 5.78k | Curl_pollset_reset(ps); |
500 | 5.78k | } |
501 | | |
502 | | struct easy_pollset *Curl_pollset_create(void) |
503 | 0 | { |
504 | 0 | struct easy_pollset *ps = curlx_calloc(1, sizeof(*ps)); |
505 | 0 | if(ps) |
506 | 0 | Curl_pollset_init(ps); |
507 | 0 | return ps; |
508 | 0 | } |
509 | | |
510 | | void Curl_pollset_cleanup(struct easy_pollset *ps) |
511 | 5.78k | { |
512 | 5.78k | #ifdef DEBUGBUILD |
513 | 5.78k | DEBUGASSERT(ps->init == CURL_EASY_POLLSET_MAGIC); |
514 | 5.78k | #endif |
515 | 5.78k | if(ps->sockets != ps->def_sockets) { |
516 | 0 | curlx_free(ps->sockets); |
517 | 0 | ps->sockets = ps->def_sockets; |
518 | 0 | } |
519 | 5.78k | if(ps->actions != ps->def_actions) { |
520 | 0 | curlx_free(ps->actions); |
521 | 0 | ps->actions = ps->def_actions; |
522 | 0 | } |
523 | 5.78k | ps->count = CURL_ARRAYSIZE(ps->def_sockets); |
524 | 5.78k | Curl_pollset_reset(ps); |
525 | 5.78k | } |
526 | | |
527 | | void Curl_pollset_move(struct easy_pollset *to, struct easy_pollset *from) |
528 | 0 | { |
529 | 0 | Curl_pollset_cleanup(to); /* deallocate anything in to */ |
530 | 0 | if(from->sockets != from->def_sockets) { |
531 | 0 | DEBUGASSERT(from->actions != from->def_actions); |
532 | 0 | to->sockets = from->sockets; |
533 | 0 | to->actions = from->actions; |
534 | 0 | to->count = from->count; |
535 | 0 | to->n = from->n; |
536 | 0 | Curl_pollset_init(from); |
537 | 0 | } |
538 | 0 | else { |
539 | 0 | DEBUGASSERT(to->sockets == to->def_sockets); |
540 | 0 | DEBUGASSERT(to->actions == to->def_actions); |
541 | 0 | memcpy(to->sockets, from->sockets, to->count * sizeof(to->sockets[0])); |
542 | 0 | memcpy(to->actions, from->actions, to->count * sizeof(to->actions[0])); |
543 | 0 | to->n = from->n; |
544 | 0 | Curl_pollset_init(from); |
545 | 0 | } |
546 | 0 | } |
547 | | |
548 | | /** |
549 | | * |
550 | | */ |
551 | | CURLcode Curl_pollset_change(struct Curl_easy *data, |
552 | | struct easy_pollset *ps, curl_socket_t sock, |
553 | | int add_flags, int remove_flags) |
554 | 3.62k | { |
555 | 3.62k | unsigned int i; |
556 | | |
557 | 3.62k | #ifdef DEBUGBUILD |
558 | 3.62k | DEBUGASSERT(ps->init == CURL_EASY_POLLSET_MAGIC); |
559 | 3.62k | #endif |
560 | | |
561 | 3.62k | DEBUGASSERT(VALID_SOCK(sock)); |
562 | 3.62k | if(!VALID_SOCK(sock)) |
563 | 0 | return CURLE_BAD_FUNCTION_ARGUMENT; |
564 | | |
565 | 3.62k | DEBUGASSERT(add_flags <= (CURL_POLL_IN | CURL_POLL_OUT)); |
566 | 3.62k | DEBUGASSERT(remove_flags <= (CURL_POLL_IN | CURL_POLL_OUT)); |
567 | 3.62k | DEBUGASSERT((add_flags & remove_flags) == 0); /* no overlap */ |
568 | 3.62k | for(i = 0; i < ps->n; ++i) { |
569 | 1.40k | if(ps->sockets[i] == sock) { |
570 | 1.40k | ps->actions[i] &= (unsigned char)(~remove_flags); |
571 | 1.40k | ps->actions[i] |= (unsigned char)add_flags; |
572 | | /* all gone? remove socket */ |
573 | 1.40k | if(!ps->actions[i]) { |
574 | 0 | if((i + 1) < ps->n) { |
575 | 0 | memmove(&ps->sockets[i], &ps->sockets[i + 1], |
576 | 0 | (ps->n - (i + 1)) * sizeof(ps->sockets[0])); |
577 | 0 | memmove(&ps->actions[i], &ps->actions[i + 1], |
578 | 0 | (ps->n - (i + 1)) * sizeof(ps->actions[0])); |
579 | 0 | } |
580 | 0 | --ps->n; |
581 | 0 | } |
582 | 1.40k | return CURLE_OK; |
583 | 1.40k | } |
584 | 1.40k | } |
585 | | /* not present */ |
586 | 2.22k | if(add_flags) { |
587 | 2.22k | if(i >= ps->count) { /* need to grow */ |
588 | 0 | unsigned int new_count = CURLMAX(ps->count * 2, 8); |
589 | 0 | curl_socket_t *nsockets; |
590 | 0 | unsigned char *nactions; |
591 | |
|
592 | 0 | CURL_TRC_M(data, "growing pollset capacity from %u to %u", |
593 | 0 | ps->count, new_count); |
594 | 0 | if(new_count <= ps->count) |
595 | 0 | return CURLE_OUT_OF_MEMORY; |
596 | 0 | nsockets = curlx_calloc(new_count, sizeof(nsockets[0])); |
597 | 0 | if(!nsockets) |
598 | 0 | return CURLE_OUT_OF_MEMORY; |
599 | 0 | nactions = curlx_calloc(new_count, sizeof(nactions[0])); |
600 | 0 | if(!nactions) { |
601 | 0 | curlx_free(nsockets); |
602 | 0 | return CURLE_OUT_OF_MEMORY; |
603 | 0 | } |
604 | 0 | memcpy(nsockets, ps->sockets, ps->count * sizeof(ps->sockets[0])); |
605 | 0 | memcpy(nactions, ps->actions, ps->count * sizeof(ps->actions[0])); |
606 | 0 | if(ps->sockets != ps->def_sockets) |
607 | 0 | curlx_free(ps->sockets); |
608 | 0 | ps->sockets = nsockets; |
609 | 0 | if(ps->actions != ps->def_actions) |
610 | 0 | curlx_free(ps->actions); |
611 | 0 | ps->actions = nactions; |
612 | 0 | ps->count = new_count; |
613 | 0 | } |
614 | 2.22k | DEBUGASSERT(i < ps->count); |
615 | 2.22k | if(i < ps->count) { |
616 | 2.22k | ps->sockets[i] = sock; |
617 | 2.22k | ps->actions[i] = (unsigned char)add_flags; |
618 | 2.22k | ps->n = i + 1; |
619 | 2.22k | } |
620 | 2.22k | } |
621 | 2.22k | return CURLE_OK; |
622 | 2.22k | } |
623 | | |
624 | | CURLcode Curl_pollset_set(struct Curl_easy *data, |
625 | | struct easy_pollset *ps, curl_socket_t sock, |
626 | | bool do_in, bool do_out) |
627 | 0 | { |
628 | 0 | return Curl_pollset_change(data, ps, sock, |
629 | 0 | (do_in ? CURL_POLL_IN : 0) | |
630 | 0 | (do_out ? CURL_POLL_OUT : 0), |
631 | 0 | (!do_in ? CURL_POLL_IN : 0) | |
632 | 0 | (!do_out ? CURL_POLL_OUT : 0)); |
633 | 0 | } |
634 | | |
635 | | void Curl_pollset_remove(struct easy_pollset *ps, curl_socket_t sock) |
636 | 0 | { |
637 | 0 | unsigned int i; |
638 | 0 | for(i = 0; i < ps->n; ++i) { |
639 | 0 | if(ps->sockets[i] == sock) { |
640 | 0 | if((i + 1) < ps->n) { |
641 | 0 | memmove(&ps->sockets[i], &ps->sockets[i + 1], |
642 | 0 | (ps->n - (i + 1)) * sizeof(ps->sockets[0])); |
643 | 0 | memmove(&ps->actions[i], &ps->actions[i + 1], |
644 | 0 | (ps->n - (i + 1)) * sizeof(ps->actions[0])); |
645 | 0 | } |
646 | 0 | --ps->n; |
647 | 0 | return; |
648 | 0 | } |
649 | 0 | } |
650 | 0 | } |
651 | | |
652 | | /* |
653 | | * Return values: |
654 | | * -1 = error |
655 | | * 0 = timeout |
656 | | * N = number of structures with non zero revent fields |
657 | | */ |
658 | | int Curl_pollset_poll(struct Curl_easy *data, |
659 | | struct easy_pollset *ps, |
660 | | timediff_t timeout_ms) |
661 | 0 | { |
662 | 0 | struct pollfd *pfds; |
663 | 0 | unsigned int i, npfds; |
664 | 0 | int rc; |
665 | |
|
666 | 0 | (void)data; |
667 | 0 | DEBUGASSERT(data); |
668 | 0 | DEBUGASSERT(data->conn); |
669 | |
|
670 | 0 | if(!ps->n) |
671 | 0 | return curlx_wait_ms(timeout_ms); |
672 | | |
673 | 0 | pfds = curlx_calloc(ps->n, sizeof(*pfds)); |
674 | 0 | if(!pfds) |
675 | 0 | return -1; |
676 | | |
677 | 0 | npfds = 0; |
678 | 0 | for(i = 0; i < ps->n; ++i) { |
679 | 0 | short events = 0; |
680 | 0 | if(ps->actions[i] & CURL_POLL_IN) { |
681 | 0 | events |= POLLIN; |
682 | 0 | } |
683 | 0 | if(ps->actions[i] & CURL_POLL_OUT) { |
684 | 0 | events |= POLLOUT; |
685 | 0 | } |
686 | 0 | if(events) { |
687 | 0 | pfds[npfds].fd = ps->sockets[i]; |
688 | 0 | pfds[npfds].events = events; |
689 | 0 | ++npfds; |
690 | 0 | } |
691 | 0 | } |
692 | |
|
693 | 0 | rc = Curl_poll(pfds, npfds, timeout_ms); |
694 | 0 | curlx_free(pfds); |
695 | 0 | return rc; |
696 | 0 | } |
697 | | |
698 | | void Curl_pollset_check(struct Curl_easy *data, |
699 | | struct easy_pollset *ps, curl_socket_t sock, |
700 | | bool *pwant_read, bool *pwant_write) |
701 | 0 | { |
702 | 0 | unsigned int i; |
703 | |
|
704 | 0 | (void)data; |
705 | 0 | DEBUGASSERT(VALID_SOCK(sock)); |
706 | 0 | for(i = 0; i < ps->n; ++i) { |
707 | 0 | if(ps->sockets[i] == sock) { |
708 | 0 | *pwant_read = !!(ps->actions[i] & CURL_POLL_IN); |
709 | 0 | *pwant_write = !!(ps->actions[i] & CURL_POLL_OUT); |
710 | 0 | return; |
711 | 0 | } |
712 | 0 | } |
713 | 0 | *pwant_read = *pwant_write = FALSE; |
714 | 0 | } |
715 | | |
716 | | bool Curl_pollset_want_recv(struct Curl_easy *data, |
717 | | struct easy_pollset *ps, |
718 | | curl_socket_t sock) |
719 | 2.14k | { |
720 | 2.14k | unsigned int i; |
721 | 2.14k | (void)data; |
722 | 3.91k | for(i = 0; i < ps->n; ++i) { |
723 | 2.14k | if((ps->sockets[i] == sock) && (ps->actions[i] & CURL_POLL_IN)) |
724 | 373 | return TRUE; |
725 | 2.14k | } |
726 | 1.77k | return FALSE; |
727 | 2.14k | } |
728 | | |
729 | | bool Curl_pollset_want_send(struct Curl_easy *data, |
730 | | struct easy_pollset *ps, |
731 | | curl_socket_t sock) |
732 | 0 | { |
733 | 0 | unsigned int i; |
734 | 0 | (void)data; |
735 | 0 | for(i = 0; i < ps->n; ++i) { |
736 | 0 | if((ps->sockets[i] == sock) && (ps->actions[i] & CURL_POLL_OUT)) |
737 | 0 | return TRUE; |
738 | 0 | } |
739 | 0 | return FALSE; |
740 | 0 | } |