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