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