diff options
author | Daniel Stenberg <daniel@haxx.se> | 2004-11-19 08:52:33 +0000 |
---|---|---|
committer | Daniel Stenberg <daniel@haxx.se> | 2004-11-19 08:52:33 +0000 |
commit | 1a05a90f1ce86394d7966aaaa9539adaa228c6bf (patch) | |
tree | 2b9cafe58b4fa7bf01d1b58a23bc5e66157d3279 /lib/select.c | |
parent | dcea109bb5ce1c8afeb0510945eb15e86cfcf1dc (diff) |
David Phillips' FD_SETSIZE fix
Diffstat (limited to 'lib/select.c')
-rw-r--r-- | lib/select.c | 231 |
1 files changed, 231 insertions, 0 deletions
diff --git a/lib/select.c b/lib/select.c new file mode 100644 index 000000000..fb337d421 --- /dev/null +++ b/lib/select.c @@ -0,0 +1,231 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" + +#ifdef HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif + +#ifndef HAVE_SELECT +#error "We can't compile without select() support!" +#endif + +#include "select.h" + +/* + * This is an internal function used for waiting for read or write + * events on single file descriptors. It attempts to replace select() + * in order to avoid limits with FD_SETSIZE. + * + * Return values: + * -1 = system call error + * 0 = timeout + * CSELECT_IN | CSELECT_OUT | CSELECT_ERR + */ +int Curl_select(int readfd, int writefd, int timeout_ms) +{ +#ifdef HAVE_POLL_FINE + struct pollfd pfd[2]; + int num; + int r; + int ret; + + num = 0; + if (readfd != CURL_SOCKET_BAD) { + pfd[num].fd = readfd; + pfd[num].events = POLLIN; + num++; + } + if (writefd != CURL_SOCKET_BAD) { + pfd[num].fd = writefd; + pfd[num].events = POLLOUT; + num++; + } + + r = poll(pfd, num, timeout_ms); + + if (r < 0) + return -1; + if (r == 0) + return 0; + + ret = 0; + num = 0; + if (readfd != CURL_SOCKET_BAD) { + if (pfd[num].revents & POLLIN) + ret |= CSELECT_IN; + if (pfd[num].revents & POLLERR) + ret |= CSELECT_ERR; + num++; + } + if (writefd != CURL_SOCKET_BAD) { + if (pfd[num].revents & POLLOUT) + ret |= CSELECT_OUT; + if (pfd[num].revents & POLLERR) + ret |= CSELECT_ERR; + } + + return ret; +#else + struct timeval timeout; + fd_set fds_read; + fd_set fds_write; + fd_set fds_err; + int maxfd; + int r; + int ret; + + timeout.tv_sec = timeout_ms / 1000; + timeout.tv_usec = (timeout_ms % 1000) * 1000; + + FD_ZERO(&fds_err); + maxfd = -1; + + FD_ZERO(&fds_read); + if (readfd != CURL_SOCKET_BAD) { + if ((readfd < 0) || (readfd >= FD_SETSIZE)) { + errno = EINVAL; + return -1; + } + FD_SET(readfd, &fds_read); + FD_SET(readfd, &fds_err); + maxfd = readfd; + } + + FD_ZERO(&fds_write); + if (writefd != CURL_SOCKET_BAD) { + if ((writefd < 0) || (writefd >= FD_SETSIZE)) { + errno = EINVAL; + return -1; + } + FD_SET(writefd, &fds_write); + FD_SET(writefd, &fds_err); + if (writefd > maxfd) + maxfd = writefd; + } + + r = select(maxfd + 1, &fds_read, &fds_write, &fds_err, &timeout); + + if (r < 0) + return -1; + if (r == 0) + return 0; + + ret = 0; + if (readfd != CURL_SOCKET_BAD) { + if (FD_ISSET(readfd, &fds_read)) + ret |= CSELECT_IN; + if (FD_ISSET(readfd, &fds_err)) + ret |= CSELECT_ERR; + } + if (writefd != CURL_SOCKET_BAD) { + if (FD_ISSET(writefd, &fds_write)) + ret |= CSELECT_OUT; + if (FD_ISSET(writefd, &fds_err)) + ret |= CSELECT_ERR; + } + + return ret; +#endif +} + +/* + * This is a wrapper around poll(). If poll() does not exist, then + * select() is used instead. An error is returned if select() is + * being used and a file descriptor too large for FD_SETSIZE. + * + * Return values: + * -1 = system call error or fd >= FD_SETSIZE + * 0 = timeout + * 1 = number of structures with non zero revent fields + */ +int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms) +{ +#ifdef HAVE_POLL_FINE + return poll(ufds, nfds, timeout_ms); +#else + struct timeval timeout; + struct timeval *ptimeout; + fd_set fds_read; + fd_set fds_write; + fd_set fds_err; + int maxfd; + int r; + unsigned int i; + + FD_ZERO(&fds_read); + FD_ZERO(&fds_write); + FD_ZERO(&fds_err); + maxfd = -1; + + for (i = 0; i < nfds; i++) { + if (ufds[i].fd < 0) + continue; + if (ufds[i].fd >= FD_SETSIZE) { + errno = EINVAL; + return -1; + } + if (ufds[i].fd > maxfd) + maxfd = ufds[i].fd; + if (ufds[i].events & POLLIN) + FD_SET(ufds[i].fd, &fds_read); + if (ufds[i].events & POLLOUT) + FD_SET(ufds[i].fd, &fds_write); + if (ufds[i].events & POLLERR) + FD_SET(ufds[i].fd, &fds_err); + } + + if (timeout_ms < 0) { + ptimeout = NULL; /* wait forever */ + } else { + timeout.tv_sec = timeout_ms / 1000; + timeout.tv_usec = (timeout_ms % 1000) * 1000; + ptimeout = &timeout; + } + + r = select(maxfd + 1, &fds_read, &fds_write, &fds_err, ptimeout); + + if (r < 0) + return -1; + if (r == 0) + return 0; + + r = 0; + for (i = 0; i < nfds; i++) { + ufds[i].revents = 0; + if (ufds[i].fd < 0) + continue; + if (FD_ISSET(ufds[i].fd, &fds_read)) + ufds[i].revents |= POLLIN; + if (FD_ISSET(ufds[i].fd, &fds_write)) + ufds[i].revents |= POLLOUT; + if (FD_ISSET(ufds[i].fd, &fds_err)) + ufds[i].revents |= POLLERR; + if (ufds[i].revents != 0) + r++; + } + + return r; +#endif +} |