1/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2021, 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 ***************************************************************************/
22
23#include "curl_setup.h"
24
25#include <limits.h>
26
27#ifdef HAVE_SYS_SELECT_H
28#include <sys/select.h>
29#elif defined(HAVE_UNISTD_H)
30#include <unistd.h>
31#endif
32
33#if !defined(HAVE_SELECT) && !defined(HAVE_POLL_FINE)
34#error "We can't compile without select() or poll() support."
35#endif
36
37#if defined(__BEOS__) && !defined(__HAIKU__)
38/* BeOS has FD_SET defined in socket.h */
39#include <socket.h>
40#endif
41
42#ifdef MSDOS
43#include <dos.h> /* delay() */
44#endif
45
46#ifdef __VXWORKS__
47#include <strings.h> /* bzero() in FD_SET */
48#endif
49
50#include <curl/curl.h>
51
52#include "urldata.h"
53#include "connect.h"
54#include "select.h"
55#include "timeval.h"
56#include "warnless.h"
57
58/*
59 * Internal function used for waiting a specific amount of ms
60 * in Curl_socket_check() and Curl_poll() when no file descriptor
61 * is provided to wait on, just being used to delay execution.
62 * WinSock select() and poll() timeout mechanisms need a valid
63 * socket descriptor in a not null file descriptor set to work.
64 * Waiting indefinitely with this function is not allowed, a
65 * zero or negative timeout value will return immediately.
66 * Timeout resolution, accuracy, as well as maximum supported
67 * value is system dependent, neither factor is a citical issue
68 * for the intended use of this function in the library.
69 *
70 * Return values:
71 * -1 = system call error, invalid timeout value, or interrupted
72 * 0 = specified timeout has elapsed
73 */
74int Curl_wait_ms(timediff_t timeout_ms)
75{
76 int r = 0;
77
78 if(!timeout_ms)
79 return 0;
80 if(timeout_ms < 0) {
81 SET_SOCKERRNO(EINVAL);
82 return -1;
83 }
84#if defined(MSDOS)
85 delay(timeout_ms);
86#elif defined(WIN32)
87 /* prevent overflow, timeout_ms is typecast to ULONG/DWORD. */
88#if TIMEDIFF_T_MAX >= ULONG_MAX
89 if(timeout_ms >= ULONG_MAX)
90 timeout_ms = ULONG_MAX-1;
91 /* don't use ULONG_MAX, because that is equal to INFINITE */
92#endif
93 Sleep((ULONG)timeout_ms);
94#else
95#if defined(HAVE_POLL_FINE)
96 /* prevent overflow, timeout_ms is typecast to int. */
97#if TIMEDIFF_T_MAX > INT_MAX
98 if(timeout_ms > INT_MAX)
99 timeout_ms = INT_MAX;
100#endif
101 r = poll(NULL, 0, (int)timeout_ms);
102#else
103 {
104 struct timeval pending_tv;
105 timediff_t tv_sec = timeout_ms / 1000;
106 timediff_t tv_usec = (timeout_ms % 1000) * 1000; /* max=999999 */
107#ifdef HAVE_SUSECONDS_T
108#if TIMEDIFF_T_MAX > TIME_T_MAX
109 /* tv_sec overflow check in case time_t is signed */
110 if(tv_sec > TIME_T_MAX)
111 tv_sec = TIME_T_MAX;
112#endif
113 pending_tv.tv_sec = (time_t)tv_sec;
114 pending_tv.tv_usec = (suseconds_t)tv_usec;
115#else
116#if TIMEDIFF_T_MAX > INT_MAX
117 /* tv_sec overflow check in case time_t is signed */
118 if(tv_sec > INT_MAX)
119 tv_sec = INT_MAX;
120#endif
121 pending_tv.tv_sec = (int)tv_sec;
122 pending_tv.tv_usec = (int)tv_usec;
123#endif
124 r = select(0, NULL, NULL, NULL, &pending_tv);
125 }
126#endif /* HAVE_POLL_FINE */
127#endif /* USE_WINSOCK */
128 if(r)
129 r = -1;
130 return r;
131}
132
133#ifndef HAVE_POLL_FINE
134/*
135 * This is a wrapper around select() to aid in Windows compatibility.
136 * A negative timeout value makes this function wait indefinitely,
137 * unless no valid file descriptor is given, when this happens the
138 * negative timeout is ignored and the function times out immediately.
139 *
140 * Return values:
141 * -1 = system call error or fd >= FD_SETSIZE
142 * 0 = timeout
143 * N = number of signalled file descriptors
144 */
145static int our_select(curl_socket_t maxfd, /* highest socket number */
146 fd_set *fds_read, /* sockets ready for reading */
147 fd_set *fds_write, /* sockets ready for writing */
148 fd_set *fds_err, /* sockets with errors */
149 timediff_t timeout_ms) /* milliseconds to wait */
150{
151 struct timeval pending_tv;
152 struct timeval *ptimeout;
153
154#ifdef USE_WINSOCK
155 /* WinSock select() can't handle zero events. See the comment below. */
156 if((!fds_read || fds_read->fd_count == 0) &&
157 (!fds_write || fds_write->fd_count == 0) &&
158 (!fds_err || fds_err->fd_count == 0)) {
159 /* no sockets, just wait */
160 return Curl_wait_ms(timeout_ms);
161 }
162#endif
163
164 ptimeout = &pending_tv;
165 if(timeout_ms < 0) {
166 ptimeout = NULL;
167 }
168 else if(timeout_ms > 0) {
169 timediff_t tv_sec = timeout_ms / 1000;
170 timediff_t tv_usec = (timeout_ms % 1000) * 1000; /* max=999999 */
171#ifdef HAVE_SUSECONDS_T
172#if TIMEDIFF_T_MAX > TIME_T_MAX
173 /* tv_sec overflow check in case time_t is signed */
174 if(tv_sec > TIME_T_MAX)
175 tv_sec = TIME_T_MAX;
176#endif
177 pending_tv.tv_sec = (time_t)tv_sec;
178 pending_tv.tv_usec = (suseconds_t)tv_usec;
179#elif defined(WIN32) /* maybe also others in the future */
180#if TIMEDIFF_T_MAX > LONG_MAX
181 /* tv_sec overflow check on Windows there we know it is long */
182 if(tv_sec > LONG_MAX)
183 tv_sec = LONG_MAX;
184#endif
185 pending_tv.tv_sec = (long)tv_sec;
186 pending_tv.tv_usec = (long)tv_usec;
187#else
188#if TIMEDIFF_T_MAX > INT_MAX
189 /* tv_sec overflow check in case time_t is signed */
190 if(tv_sec > INT_MAX)
191 tv_sec = INT_MAX;
192#endif
193 pending_tv.tv_sec = (int)tv_sec;
194 pending_tv.tv_usec = (int)tv_usec;
195#endif
196 }
197 else {
198 pending_tv.tv_sec = 0;
199 pending_tv.tv_usec = 0;
200 }
201
202#ifdef USE_WINSOCK
203 /* WinSock select() must not be called with an fd_set that contains zero
204 fd flags, or it will return WSAEINVAL. But, it also can't be called
205 with no fd_sets at all! From the documentation:
206
207 Any two of the parameters, readfds, writefds, or exceptfds, can be
208 given as null. At least one must be non-null, and any non-null
209 descriptor set must contain at least one handle to a socket.
210
211 It is unclear why WinSock doesn't just handle this for us instead of
212 calling this an error. Luckily, with WinSock, we can _also_ ask how
213 many bits are set on an fd_set. So, let's just check it beforehand.
214 */
215 return select((int)maxfd + 1,
216 fds_read && fds_read->fd_count ? fds_read : NULL,
217 fds_write && fds_write->fd_count ? fds_write : NULL,
218 fds_err && fds_err->fd_count ? fds_err : NULL, ptimeout);
219#else
220 return select((int)maxfd + 1, fds_read, fds_write, fds_err, ptimeout);
221#endif
222}
223
224#endif
225
226/*
227 * Wait for read or write events on a set of file descriptors. It uses poll()
228 * when a fine poll() is available, in order to avoid limits with FD_SETSIZE,
229 * otherwise select() is used. An error is returned if select() is being used
230 * and a file descriptor is too large for FD_SETSIZE.
231 *
232 * A negative timeout value makes this function wait indefinitely,
233 * unless no valid file descriptor is given, when this happens the
234 * negative timeout is ignored and the function times out immediately.
235 *
236 * Return values:
237 * -1 = system call error or fd >= FD_SETSIZE
238 * 0 = timeout
239 * [bitmask] = action as described below
240 *
241 * CURL_CSELECT_IN - first socket is readable
242 * CURL_CSELECT_IN2 - second socket is readable
243 * CURL_CSELECT_OUT - write socket is writable
244 * CURL_CSELECT_ERR - an error condition occurred
245 */
246int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */
247 curl_socket_t readfd1,
248 curl_socket_t writefd, /* socket to write to */
249 timediff_t timeout_ms) /* milliseconds to wait */
250{
251 struct pollfd pfd[3];
252 int num;
253 int r;
254
255 if((readfd0 == CURL_SOCKET_BAD) && (readfd1 == CURL_SOCKET_BAD) &&
256 (writefd == CURL_SOCKET_BAD)) {
257 /* no sockets, just wait */
258 return Curl_wait_ms(timeout_ms);
259 }
260
261 /* Avoid initial timestamp, avoid Curl_now() call, when elapsed
262 time in this function does not need to be measured. This happens
263 when function is called with a zero timeout or a negative timeout
264 value indicating a blocking call should be performed. */
265
266 num = 0;
267 if(readfd0 != CURL_SOCKET_BAD) {
268 pfd[num].fd = readfd0;
269 pfd[num].events = POLLRDNORM|POLLIN|POLLRDBAND|POLLPRI;
270 pfd[num].revents = 0;
271 num++;
272 }
273 if(readfd1 != CURL_SOCKET_BAD) {
274 pfd[num].fd = readfd1;
275 pfd[num].events = POLLRDNORM|POLLIN|POLLRDBAND|POLLPRI;
276 pfd[num].revents = 0;
277 num++;
278 }
279 if(writefd != CURL_SOCKET_BAD) {
280 pfd[num].fd = writefd;
281 pfd[num].events = POLLWRNORM|POLLOUT|POLLPRI;
282 pfd[num].revents = 0;
283 num++;
284 }
285
286 r = Curl_poll(pfd, num, timeout_ms);
287 if(r <= 0)
288 return r;
289
290 r = 0;
291 num = 0;
292 if(readfd0 != CURL_SOCKET_BAD) {
293 if(pfd[num].revents & (POLLRDNORM|POLLIN|POLLERR|POLLHUP))
294 r |= CURL_CSELECT_IN;
295 if(pfd[num].revents & (POLLRDBAND|POLLPRI|POLLNVAL))
296 r |= CURL_CSELECT_ERR;
297 num++;
298 }
299 if(readfd1 != CURL_SOCKET_BAD) {
300 if(pfd[num].revents & (POLLRDNORM|POLLIN|POLLERR|POLLHUP))
301 r |= CURL_CSELECT_IN2;
302 if(pfd[num].revents & (POLLRDBAND|POLLPRI|POLLNVAL))
303 r |= CURL_CSELECT_ERR;
304 num++;
305 }
306 if(writefd != CURL_SOCKET_BAD) {
307 if(pfd[num].revents & (POLLWRNORM|POLLOUT))
308 r |= CURL_CSELECT_OUT;
309 if(pfd[num].revents & (POLLERR|POLLHUP|POLLPRI|POLLNVAL))
310 r |= CURL_CSELECT_ERR;
311 }
312
313 return r;
314}
315
316/*
317 * This is a wrapper around poll(). If poll() does not exist, then
318 * select() is used instead. An error is returned if select() is
319 * being used and a file descriptor is too large for FD_SETSIZE.
320 * A negative timeout value makes this function wait indefinitely,
321 * unless no valid file descriptor is given, when this happens the
322 * negative timeout is ignored and the function times out immediately.
323 *
324 * Return values:
325 * -1 = system call error or fd >= FD_SETSIZE
326 * 0 = timeout
327 * N = number of structures with non zero revent fields
328 */
329int Curl_poll(struct pollfd ufds[], unsigned int nfds, timediff_t timeout_ms)
330{
331#ifdef HAVE_POLL_FINE
332 int pending_ms;
333#else
334 fd_set fds_read;
335 fd_set fds_write;
336 fd_set fds_err;
337 curl_socket_t maxfd;
338#endif
339 bool fds_none = TRUE;
340 unsigned int i;
341 int r;
342
343 if(ufds) {
344 for(i = 0; i < nfds; i++) {
345 if(ufds[i].fd != CURL_SOCKET_BAD) {
346 fds_none = FALSE;
347 break;
348 }
349 }
350 }
351 if(fds_none) {
352 /* no sockets, just wait */
353 return Curl_wait_ms(timeout_ms);
354 }
355
356 /* Avoid initial timestamp, avoid Curl_now() call, when elapsed
357 time in this function does not need to be measured. This happens
358 when function is called with a zero timeout or a negative timeout
359 value indicating a blocking call should be performed. */
360
361#ifdef HAVE_POLL_FINE
362
363 /* prevent overflow, timeout_ms is typecast to int. */
364#if TIMEDIFF_T_MAX > INT_MAX
365 if(timeout_ms > INT_MAX)
366 timeout_ms = INT_MAX;
367#endif
368 if(timeout_ms > 0)
369 pending_ms = (int)timeout_ms;
370 else if(timeout_ms < 0)
371 pending_ms = -1;
372 else
373 pending_ms = 0;
374 r = poll(ufds, nfds, pending_ms);
375 if(r <= 0)
376 return r;
377
378 for(i = 0; i < nfds; i++) {
379 if(ufds[i].fd == CURL_SOCKET_BAD)
380 continue;
381 if(ufds[i].revents & POLLHUP)
382 ufds[i].revents |= POLLIN;
383 if(ufds[i].revents & POLLERR)
384 ufds[i].revents |= POLLIN|POLLOUT;
385 }
386
387#else /* HAVE_POLL_FINE */
388
389 FD_ZERO(&fds_read);
390 FD_ZERO(&fds_write);
391 FD_ZERO(&fds_err);
392 maxfd = (curl_socket_t)-1;
393
394 for(i = 0; i < nfds; i++) {
395 ufds[i].revents = 0;
396 if(ufds[i].fd == CURL_SOCKET_BAD)
397 continue;
398 VERIFY_SOCK(ufds[i].fd);
399 if(ufds[i].events & (POLLIN|POLLOUT|POLLPRI|
400 POLLRDNORM|POLLWRNORM|POLLRDBAND)) {
401 if(ufds[i].fd > maxfd)
402 maxfd = ufds[i].fd;
403 if(ufds[i].events & (POLLRDNORM|POLLIN))
404 FD_SET(ufds[i].fd, &fds_read);
405 if(ufds[i].events & (POLLWRNORM|POLLOUT))
406 FD_SET(ufds[i].fd, &fds_write);
407 if(ufds[i].events & (POLLRDBAND|POLLPRI))
408 FD_SET(ufds[i].fd, &fds_err);
409 }
410 }
411
412 /*
413 Note also that WinSock ignores the first argument, so we don't worry
414 about the fact that maxfd is computed incorrectly with WinSock (since
415 curl_socket_t is unsigned in such cases and thus -1 is the largest
416 value).
417 */
418 r = our_select(maxfd, &fds_read, &fds_write, &fds_err, timeout_ms);
419 if(r <= 0)
420 return r;
421
422 r = 0;
423 for(i = 0; i < nfds; i++) {
424 ufds[i].revents = 0;
425 if(ufds[i].fd == CURL_SOCKET_BAD)
426 continue;
427 if(FD_ISSET(ufds[i].fd, &fds_read)) {
428 if(ufds[i].events & POLLRDNORM)
429 ufds[i].revents |= POLLRDNORM;
430 if(ufds[i].events & POLLIN)
431 ufds[i].revents |= POLLIN;
432 }
433 if(FD_ISSET(ufds[i].fd, &fds_write)) {
434 if(ufds[i].events & POLLWRNORM)
435 ufds[i].revents |= POLLWRNORM;
436 if(ufds[i].events & POLLOUT)
437 ufds[i].revents |= POLLOUT;
438 }
439 if(FD_ISSET(ufds[i].fd, &fds_err)) {
440 if(ufds[i].events & POLLRDBAND)
441 ufds[i].revents |= POLLRDBAND;
442 if(ufds[i].events & POLLPRI)
443 ufds[i].revents |= POLLPRI;
444 }
445 if(ufds[i].revents)
446 r++;
447 }
448
449#endif /* HAVE_POLL_FINE */
450
451 return r;
452}
453
454#ifdef TPF
455/*
456 * This is a replacement for select() on the TPF platform.
457 * It is used whenever libcurl calls select().
458 * The call below to tpf_process_signals() is required because
459 * TPF's select calls are not signal interruptible.
460 *
461 * Return values are the same as select's.
462 */
463int tpf_select_libcurl(int maxfds, fd_set *reads, fd_set *writes,
464 fd_set *excepts, struct timeval *tv)
465{
466 int rc;
467
468 rc = tpf_select_bsd(maxfds, reads, writes, excepts, tv);
469 tpf_process_signals();
470 return rc;
471}
472#endif /* TPF */
473