1/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2022, 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#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 can't 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
51/*
52 * Internal function used for waiting a specific amount of ms
53 * in Curl_socket_check() and Curl_poll() when no file descriptor
54 * is provided to wait on, just being used to delay execution.
55 * WinSock select() and poll() timeout mechanisms need a valid
56 * socket descriptor in a not null file descriptor set to work.
57 * Waiting indefinitely with this function is not allowed, a
58 * zero or negative timeout value will return immediately.
59 * Timeout resolution, accuracy, as well as maximum supported
60 * value is system dependent, neither factor is a critical issue
61 * for the intended use of this function in the library.
62 *
63 * Return values:
64 * -1 = system call error, invalid timeout value, or interrupted
65 * 0 = specified timeout has elapsed
66 */
67int Curl_wait_ms(timediff_t timeout_ms)
68{
69 int r = 0;
70
71 if(!timeout_ms)
72 return 0;
73 if(timeout_ms < 0) {
74 SET_SOCKERRNO(EINVAL);
75 return -1;
76 }
77#if defined(MSDOS)
78 delay(timeout_ms);
79#elif defined(WIN32)
80 /* prevent overflow, timeout_ms is typecast to ULONG/DWORD. */
81#if TIMEDIFF_T_MAX >= ULONG_MAX
82 if(timeout_ms >= ULONG_MAX)
83 timeout_ms = ULONG_MAX-1;
84 /* don't use ULONG_MAX, because that is equal to INFINITE */
85#endif
86 Sleep((ULONG)timeout_ms);
87#else
88#if defined(HAVE_POLL_FINE)
89 /* prevent overflow, timeout_ms is typecast to int. */
90#if TIMEDIFF_T_MAX > INT_MAX
91 if(timeout_ms > INT_MAX)
92 timeout_ms = INT_MAX;
93#endif
94 r = poll(NULL, 0, (int)timeout_ms);
95#else
96 {
97 struct timeval pending_tv;
98 r = select(0, NULL, NULL, NULL, curlx_mstotv(&pending_tv, timeout_ms));
99 }
100#endif /* HAVE_POLL_FINE */
101#endif /* USE_WINSOCK */
102 if(r)
103 r = -1;
104 return r;
105}
106
107#ifndef HAVE_POLL_FINE
108/*
109 * This is a wrapper around select() to aid in Windows compatibility.
110 * A negative timeout value makes this function wait indefinitely,
111 * unless no valid file descriptor is given, when this happens the
112 * negative timeout is ignored and the function times out immediately.
113 *
114 * Return values:
115 * -1 = system call error or fd >= FD_SETSIZE
116 * 0 = timeout
117 * N = number of signalled file descriptors
118 */
119static int our_select(curl_socket_t maxfd, /* highest socket number */
120 fd_set *fds_read, /* sockets ready for reading */
121 fd_set *fds_write, /* sockets ready for writing */
122 fd_set *fds_err, /* sockets with errors */
123 timediff_t timeout_ms) /* milliseconds to wait */
124{
125 struct timeval pending_tv;
126 struct timeval *ptimeout;
127
128#ifdef USE_WINSOCK
129 /* WinSock select() can't handle zero events. See the comment below. */
130 if((!fds_read || fds_read->fd_count == 0) &&
131 (!fds_write || fds_write->fd_count == 0) &&
132 (!fds_err || fds_err->fd_count == 0)) {
133 /* no sockets, just wait */
134 return Curl_wait_ms(timeout_ms);
135 }
136#endif
137
138 ptimeout = curlx_mstotv(&pending_tv, timeout_ms);
139
140#ifdef USE_WINSOCK
141 /* WinSock select() must not be called with an fd_set that contains zero
142 fd flags, or it will return WSAEINVAL. But, it also can't be called
143 with no fd_sets at all! From the documentation:
144
145 Any two of the parameters, readfds, writefds, or exceptfds, can be
146 given as null. At least one must be non-null, and any non-null
147 descriptor set must contain at least one handle to a socket.
148
149 It is unclear why WinSock doesn't just handle this for us instead of
150 calling this an error. Luckily, with WinSock, we can _also_ ask how
151 many bits are set on an fd_set. So, let's just check it beforehand.
152 */
153 return select((int)maxfd + 1,
154 fds_read && fds_read->fd_count ? fds_read : NULL,
155 fds_write && fds_write->fd_count ? fds_write : NULL,
156 fds_err && fds_err->fd_count ? fds_err : NULL, ptimeout);
157#else
158 return select((int)maxfd + 1, fds_read, fds_write, fds_err, ptimeout);
159#endif
160}
161
162#endif
163
164/*
165 * Wait for read or write events on a set of file descriptors. It uses poll()
166 * when a fine poll() is available, in order to avoid limits with FD_SETSIZE,
167 * otherwise select() is used. An error is returned if select() is being used
168 * and a file descriptor is too large for FD_SETSIZE.
169 *
170 * A negative timeout value makes this function wait indefinitely,
171 * unless no valid file descriptor is given, when this happens the
172 * negative timeout is ignored and the function times out immediately.
173 *
174 * Return values:
175 * -1 = system call error or fd >= FD_SETSIZE
176 * 0 = timeout
177 * [bitmask] = action as described below
178 *
179 * CURL_CSELECT_IN - first socket is readable
180 * CURL_CSELECT_IN2 - second socket is readable
181 * CURL_CSELECT_OUT - write socket is writable
182 * CURL_CSELECT_ERR - an error condition occurred
183 */
184int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */
185 curl_socket_t readfd1,
186 curl_socket_t writefd, /* socket to write to */
187 timediff_t timeout_ms) /* milliseconds to wait */
188{
189 struct pollfd pfd[3];
190 int num;
191 int r;
192
193 if((readfd0 == CURL_SOCKET_BAD) && (readfd1 == CURL_SOCKET_BAD) &&
194 (writefd == CURL_SOCKET_BAD)) {
195 /* no sockets, just wait */
196 return Curl_wait_ms(timeout_ms);
197 }
198
199 /* Avoid initial timestamp, avoid Curl_now() call, when elapsed
200 time in this function does not need to be measured. This happens
201 when function is called with a zero timeout or a negative timeout
202 value indicating a blocking call should be performed. */
203
204 num = 0;
205 if(readfd0 != CURL_SOCKET_BAD) {
206 pfd[num].fd = readfd0;
207 pfd[num].events = POLLRDNORM|POLLIN|POLLRDBAND|POLLPRI;
208 pfd[num].revents = 0;
209 num++;
210 }
211 if(readfd1 != CURL_SOCKET_BAD) {
212 pfd[num].fd = readfd1;
213 pfd[num].events = POLLRDNORM|POLLIN|POLLRDBAND|POLLPRI;
214 pfd[num].revents = 0;
215 num++;
216 }
217 if(writefd != CURL_SOCKET_BAD) {
218 pfd[num].fd = writefd;
219 pfd[num].events = POLLWRNORM|POLLOUT|POLLPRI;
220 pfd[num].revents = 0;
221 num++;
222 }
223
224 r = Curl_poll(pfd, num, timeout_ms);
225 if(r <= 0)
226 return r;
227
228 r = 0;
229 num = 0;
230 if(readfd0 != CURL_SOCKET_BAD) {
231 if(pfd[num].revents & (POLLRDNORM|POLLIN|POLLERR|POLLHUP))
232 r |= CURL_CSELECT_IN;
233 if(pfd[num].revents & (POLLRDBAND|POLLPRI|POLLNVAL))
234 r |= CURL_CSELECT_ERR;
235 num++;
236 }
237 if(readfd1 != CURL_SOCKET_BAD) {
238 if(pfd[num].revents & (POLLRDNORM|POLLIN|POLLERR|POLLHUP))
239 r |= CURL_CSELECT_IN2;
240 if(pfd[num].revents & (POLLRDBAND|POLLPRI|POLLNVAL))
241 r |= CURL_CSELECT_ERR;
242 num++;
243 }
244 if(writefd != CURL_SOCKET_BAD) {
245 if(pfd[num].revents & (POLLWRNORM|POLLOUT))
246 r |= CURL_CSELECT_OUT;
247 if(pfd[num].revents & (POLLERR|POLLHUP|POLLPRI|POLLNVAL))
248 r |= CURL_CSELECT_ERR;
249 }
250
251 return r;
252}
253
254/*
255 * This is a wrapper around poll(). If poll() does not exist, then
256 * select() is used instead. An error is returned if select() is
257 * being used and a file descriptor is too large for FD_SETSIZE.
258 * A negative timeout value makes this function wait indefinitely,
259 * unless no valid file descriptor is given, when this happens the
260 * negative timeout is ignored and the function times out immediately.
261 *
262 * Return values:
263 * -1 = system call error or fd >= FD_SETSIZE
264 * 0 = timeout
265 * N = number of structures with non zero revent fields
266 */
267int Curl_poll(struct pollfd ufds[], unsigned int nfds, timediff_t timeout_ms)
268{
269#ifdef HAVE_POLL_FINE
270 int pending_ms;
271#else
272 fd_set fds_read;
273 fd_set fds_write;
274 fd_set fds_err;
275 curl_socket_t maxfd;
276#endif
277 bool fds_none = TRUE;
278 unsigned int i;
279 int r;
280
281 if(ufds) {
282 for(i = 0; i < nfds; i++) {
283 if(ufds[i].fd != CURL_SOCKET_BAD) {
284 fds_none = FALSE;
285 break;
286 }
287 }
288 }
289 if(fds_none) {
290 /* no sockets, just wait */
291 return Curl_wait_ms(timeout_ms);
292 }
293
294 /* Avoid initial timestamp, avoid Curl_now() call, when elapsed
295 time in this function does not need to be measured. This happens
296 when function is called with a zero timeout or a negative timeout
297 value indicating a blocking call should be performed. */
298
299#ifdef HAVE_POLL_FINE
300
301 /* prevent overflow, timeout_ms is typecast to int. */
302#if TIMEDIFF_T_MAX > INT_MAX
303 if(timeout_ms > INT_MAX)
304 timeout_ms = INT_MAX;
305#endif
306 if(timeout_ms > 0)
307 pending_ms = (int)timeout_ms;
308 else if(timeout_ms < 0)
309 pending_ms = -1;
310 else
311 pending_ms = 0;
312 r = poll(ufds, nfds, pending_ms);
313 if(r <= 0) {
314 if((r == -1) && (SOCKERRNO == EINTR))
315 /* make EINTR from select or poll not a "lethal" error */
316 r = 0;
317 return r;
318 }
319
320 for(i = 0; i < nfds; i++) {
321 if(ufds[i].fd == CURL_SOCKET_BAD)
322 continue;
323 if(ufds[i].revents & POLLHUP)
324 ufds[i].revents |= POLLIN;
325 if(ufds[i].revents & POLLERR)
326 ufds[i].revents |= POLLIN|POLLOUT;
327 }
328
329#else /* HAVE_POLL_FINE */
330
331 FD_ZERO(&fds_read);
332 FD_ZERO(&fds_write);
333 FD_ZERO(&fds_err);
334 maxfd = (curl_socket_t)-1;
335
336 for(i = 0; i < nfds; i++) {
337 ufds[i].revents = 0;
338 if(ufds[i].fd == CURL_SOCKET_BAD)
339 continue;
340 VERIFY_SOCK(ufds[i].fd);
341 if(ufds[i].events & (POLLIN|POLLOUT|POLLPRI|
342 POLLRDNORM|POLLWRNORM|POLLRDBAND)) {
343 if(ufds[i].fd > maxfd)
344 maxfd = ufds[i].fd;
345 if(ufds[i].events & (POLLRDNORM|POLLIN))
346 FD_SET(ufds[i].fd, &fds_read);
347 if(ufds[i].events & (POLLWRNORM|POLLOUT))
348 FD_SET(ufds[i].fd, &fds_write);
349 if(ufds[i].events & (POLLRDBAND|POLLPRI))
350 FD_SET(ufds[i].fd, &fds_err);
351 }
352 }
353
354 /*
355 Note also that WinSock ignores the first argument, so we don't worry
356 about the fact that maxfd is computed incorrectly with WinSock (since
357 curl_socket_t is unsigned in such cases and thus -1 is the largest
358 value).
359 */
360 r = our_select(maxfd, &fds_read, &fds_write, &fds_err, timeout_ms);
361 if(r <= 0) {
362 if((r == -1) && (SOCKERRNO == EINTR))
363 /* make EINTR from select or poll not a "lethal" error */
364 r = 0;
365 return r;
366 }
367
368 r = 0;
369 for(i = 0; i < nfds; i++) {
370 ufds[i].revents = 0;
371 if(ufds[i].fd == CURL_SOCKET_BAD)
372 continue;
373 if(FD_ISSET(ufds[i].fd, &fds_read)) {
374 if(ufds[i].events & POLLRDNORM)
375 ufds[i].revents |= POLLRDNORM;
376 if(ufds[i].events & POLLIN)
377 ufds[i].revents |= POLLIN;
378 }
379 if(FD_ISSET(ufds[i].fd, &fds_write)) {
380 if(ufds[i].events & POLLWRNORM)
381 ufds[i].revents |= POLLWRNORM;
382 if(ufds[i].events & POLLOUT)
383 ufds[i].revents |= POLLOUT;
384 }
385 if(FD_ISSET(ufds[i].fd, &fds_err)) {
386 if(ufds[i].events & POLLRDBAND)
387 ufds[i].revents |= POLLRDBAND;
388 if(ufds[i].events & POLLPRI)
389 ufds[i].revents |= POLLPRI;
390 }
391 if(ufds[i].revents)
392 r++;
393 }
394
395#endif /* HAVE_POLL_FINE */
396
397 return r;
398}
399