File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / curl / lib / select.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 3 10:01:15 2020 UTC (5 years ago) by misho
Branches: curl, MAIN
CVS tags: v7_70_0p4, HEAD
curl

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>