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