blob: a8c471e2db495ea7b005f79865ed8f89598f3b12 [file] [log] [blame]
/* ====================================================================
* Copyright (c) 1999 Ralf S. Engelschall. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RALF S. ENGELSCHALL OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*/
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <time.h>
#include <errno.h>
#include <unistd.h>
#include "poll.h"
/*
* Emulate SysV poll(2) with BSD select(2)
* Written in June 1999 by Ralf S. Engelschall <rse@engelschall.com>
*/
int poll(struct pollfd *pfd, unsigned int nfd, int timeout)
{
fd_set rfds, wfds, efds;
struct timeval tv, *ptv;
int maxfd, rc, i, ok;
char data[64];
/* poll(2) semantics */
if (pfd == NULL) {
errno = EFAULT;
return -1;
}
/* convert timeout number into a timeval structure */
ptv = &tv;
if (timeout == 0) {
/* return immediately */
ptv->tv_sec = 0;
ptv->tv_usec = 0;
}
else if (timeout == INFTIM) {
/* wait forever */
ptv = NULL;
}
else {
/* return after timeout */
ptv->tv_sec = timeout / 1000;
ptv->tv_usec = (timeout % 1000) * 1000;
}
/* clean illegal fd set and (re)enter the repeat loop */
/* create fd sets and determine max fd */
maxfd = 0;
FD_ZERO(&rfds);
FD_ZERO(&wfds);
FD_ZERO(&efds);
for(i = 0; i < nfd; i++) {
if (pfd[i].fd < 0) {
continue;
}
if (pfd[i].events & POLLIN)
FD_SET(pfd[i].fd, &rfds);
if (pfd[i].events & POLLOUT)
FD_SET(pfd[i].fd, &wfds);
if (pfd[i].events & POLLPRI)
FD_SET(pfd[i].fd, &efds);
if (pfd[i].fd >= maxfd && (pfd[i].events & (POLLIN|POLLOUT|POLLPRI)))
maxfd = pfd[i].fd;
}
/* examine fd sets */
rc = select(maxfd+1, &rfds, &wfds, &efds, ptv);
/* establish results */
if (rc > 0) {
rc = 0;
for (i = 0; i < nfd; i++) {
ok = 0;
pfd[i].revents = 0;
if (pfd[i].fd < 0) {
/* support for POLLNVAL */
pfd[i].revents |= POLLNVAL;
continue;
}
if (FD_ISSET(pfd[i].fd, &rfds)) {
pfd[i].revents |= POLLIN;
ok++;
/* support for POLLHUP */
if (recv(pfd[i].fd, data, 0, 0) == -1) {
if ( errno == ESHUTDOWN || errno == ECONNRESET
|| errno == ECONNABORTED || errno == ENETRESET) {
pfd[i].revents &= ~(POLLIN);
pfd[i].revents |= POLLHUP;
ok--;
}
}
}
if (FD_ISSET(pfd[i].fd, &wfds)) {
pfd[i].revents |= POLLOUT;
ok++;
}
if (FD_ISSET(pfd[i].fd, &efds)) {
pfd[i].revents |= POLLPRI;
ok++;
}
if (ok)
rc++;
}
}
return rc;
}