Fix compilation error on BeOS.
[gnulib.git] / lib / poll.c
index bc200f5..ed81dba 100644 (file)
@@ -1,7 +1,7 @@
 /* Emulation for poll(2)
    Contributed by Paolo Bonzini.
 
-   Copyright 2001, 2002, 2003 Free Software Foundation, Inc.
+   Copyright 2001, 2002, 2003, 2006, 2007 Free Software Foundation, Inc.
 
    This file is part of gnulib.
 
@@ -19,9 +19,7 @@
    with this program; if not, write to the Free Software Foundation,
    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
 
-#ifdef HAVE_CONFIG_H
 #include "config.h"
-#endif
 
 #include <sys/types.h>
 #include "poll.h"
 #include <sys/select.h>
 #include <unistd.h>
 
-#if TIME_WITH_SYS_TIME
-# include <sys/time.h>
-# include <time.h>
-#else
-# if HAVE_SYS_TIME_H
-#  include <sys/time.h>
-# else
-#  include <time.h>
-# endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#ifdef HAVE_SYS_FILIO_H
+#include <sys/filio.h>
 #endif
 
+#include <sys/time.h>
+#include <time.h>
+
 #ifndef INFTIM
 #define INFTIM (-1)
 #endif
 #define EOVERFLOW EINVAL
 #endif
 
+/* BeOS does not have MSG_PEEK.  */
+#ifndef MSG_PEEK
+#define MSG_PEEK 0
+#endif
+
 int
 poll (pfd, nfd, timeout)
      struct pollfd *pfd;
@@ -58,9 +60,8 @@ poll (pfd, nfd, timeout)
 {
   fd_set rfds, wfds, efds;
   struct timeval tv, *ptv;
-  int maxfd, rc, happened;
+  int maxfd, rc;
   nfds_t i;
-  char data[64];
 
 #ifdef _SC_OPEN_MAX
   if (nfd > sysconf (_SC_OPEN_MAX))
@@ -129,52 +130,77 @@ poll (pfd, nfd, timeout)
                               | POLLWRNORM | POLLWRBAND)))
        {
          maxfd = pfd[i].fd;
+
+         /* Windows use a linear array of sockets (of size FD_SETSIZE). The
+            descriptor value is not used to address the array.  */ 
+#if defined __CYGWIN__ || (!defined _WIN32 && !defined __WIN32__)
          if (maxfd > FD_SETSIZE)
            {
              errno = EOVERFLOW;
              return -1;
            }
+#endif
        }
     }
 
   /* examine fd sets */
   rc = select (maxfd + 1, &rfds, &wfds, &efds, ptv);
+  if (rc < 0)
+    return rc;
 
   /* establish results */
-  if (rc > 0)
-    {
-      rc = 0;
-      for (i = 0; i < nfd; i++)
-       {
-         pfd[i].revents = 0;
-         if (pfd[i].fd < 0)
-           continue;
-
-         happened = 0;
-         if (FD_ISSET (pfd[i].fd, &rfds))
-           {
-             /* support for POLLHUP.  An hung up descriptor does not
-                increase the return value! */
-             if (recv (pfd[i].fd, data, 64, MSG_PEEK) == -1)
-               {
-                 if (errno == ESHUTDOWN || errno == ECONNRESET
-                     || errno == ECONNABORTED || errno == ENETRESET)
-                   pfd[i].revents |= POLLHUP;
-               }
-             else
-               happened |= POLLIN | POLLRDNORM;
-           }
-
-         if (FD_ISSET (pfd[i].fd, &wfds))
-           happened |= POLLOUT | POLLWRNORM | POLLWRBAND;
-
-         if (FD_ISSET (pfd[i].fd, &efds))
-           happened |= POLLPRI | POLLRDBAND;
-
-         pfd[i].revents |= pfd[i].events & happened;
-         rc += (happened > 0);
-       }
-    }
+  rc = 0;
+  for (i = 0; i < nfd; i++)
+    if (pfd[i].fd < 0)
+      pfd[i].revents = 0;
+    else
+      {
+       int happened = 0, sought = pfd[i].events;
+       if (FD_ISSET (pfd[i].fd, &rfds))
+         {
+           int r;
+
+#if defined __MACH__ && defined __APPLE__
+           /* There is a bug in Mac OS X that causes it to ignore MSG_PEEK
+              for some kinds of descriptors.  Detect if this descriptor is a
+              connected socket, a server socket, or something else using a
+              0-byte recv, and use ioctl(2) to detect POLLHUP.  */
+           r = recv (pfd[i].fd, NULL, 0, MSG_PEEK);
+           if (r == 0 || errno == ENOTSOCK)
+             ioctl(pfd[i].fd, FIONREAD, &r);
+#else
+           char data[64];
+           r = recv (pfd[i].fd, data, sizeof (data), MSG_PEEK);
+#endif
+           if (r == 0)
+             happened |= POLLHUP;
+
+           /* If the event happened on an unconnected server socket,
+              that's fine. */
+           else if (r > 0 || ( /* (r == -1) && */ errno == ENOTCONN))
+             happened |= (POLLIN | POLLRDNORM) & sought;
+
+           /* Distinguish hung-up sockets from other errors.  */
+           else if (errno == ESHUTDOWN || errno == ECONNRESET
+                    || errno == ECONNABORTED || errno == ENETRESET)
+             happened |= POLLHUP;
+
+           else
+             happened |= POLLERR;
+         }
+
+       if (FD_ISSET (pfd[i].fd, &wfds))
+         happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;
+
+       if (FD_ISSET (pfd[i].fd, &efds))
+         happened |= (POLLPRI | POLLRDBAND) & sought;
+
+       if (happened)
+         {
+           pfd[i].revents = happened;
+           rc++;
+         }
+      }
 
   return rc;
 }