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, 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 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(pfd, 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(ufds, nfds, 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