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