Reformat: delete trailing whitespace
[yazpp-moved-to-github.git] / src / yaz-socket-manager.cpp
index bfee990..0a3797a 100644 (file)
@@ -1,13 +1,11 @@
-/*
- * Copyright (c) 1998-2005, Index Data.
+/* This file is part of the yazpp toolkit.
+ * Copyright (C) 1998-2012 Index Data and Mike Taylor
  * See the file LICENSE for details.
- * 
- * $Id: yaz-socket-manager.cpp,v 1.35 2005-06-25 15:53:19 adam Exp $
  */
-#ifdef WIN32
-#include <winsock.h>
-#endif
 
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
 #if HAVE_SYS_TIME_H
 #include <sys/time.h>
 #endif
 #include <errno.h>
 #include <string.h>
 #include <assert.h>
+#include <stdlib.h>
 
 #include <yaz/log.h>
-#include <yaz++/socket-manager.h>
+
+#include <yazpp/socket-manager.h>
+#include <yaz/poll.h>
 
 using namespace yazpp_1;
 
@@ -31,13 +32,22 @@ SocketManager::SocketEntry **SocketManager::lookupObserver(
     ISocketObserver *observer)
 {
     SocketEntry **se;
-    
+
     for (se = &m_observers; *se; se = &(*se)->next)
         if ((*se)->observer == observer)
             break;
     return se;
 }
 
+int SocketManager::getNumberOfObservers()
+{
+    int i = 0;
+    SocketEntry *se;
+    for (se = m_observers; se; se = se->next, i++)
+        ;
+    return i;
+}
+
 void SocketManager::addObserver(int fd, ISocketObserver *observer)
 {
     SocketEntry *se;
@@ -71,7 +81,7 @@ void SocketManager::deleteObserver(ISocketObserver *observer)
 void SocketManager::deleteObservers()
 {
     SocketEntry *se = m_observers;
-    
+
     while (se)
     {
         SocketEntry *se_next = se->next;
@@ -105,6 +115,85 @@ void SocketManager::timeoutObserver(ISocketObserver *observer,
         se->timeout = timeout;
 }
 
+
+void SocketManager::inspect_poll_result(int res, struct yaz_poll_fd *fds,
+                                        int no_fds, int timeout)
+
+{
+    yaz_log(m_log, "yaz_poll returned res=%d", res);
+    time_t now = time(0);
+    int i;
+    int no_put_events = 0;
+    int no_lost_observers = 0;
+
+    for (i = 0; i < no_fds; i++)
+    {
+        SocketEntry *p;
+        for (p = m_observers; p; p = p->next)
+            if (p->fd == fds[i].fd)
+                break;
+        if (!p)
+        {
+            // m_observers list changed since poll started
+            no_lost_observers++;
+            continue;
+        }
+
+        enum yaz_poll_mask output_mask = fds[i].output_mask;
+
+        int mask = 0;
+        if (output_mask & yaz_poll_read)
+            mask |= SOCKET_OBSERVE_READ;
+
+        if (output_mask & yaz_poll_write)
+            mask |= SOCKET_OBSERVE_WRITE;
+
+        if (output_mask & yaz_poll_except)
+            mask |= SOCKET_OBSERVE_EXCEPT;
+
+        if (mask)
+        {
+            SocketEvent *event = new SocketEvent;
+            p->last_activity = now;
+            event->observer = p->observer;
+            event->event = mask;
+            putEvent (event);
+            no_put_events++;
+            yaz_log (m_log, "putEvent I/O mask=%d", mask);
+        }
+        else if (res == 0 && p->timeout_this == timeout)
+        {
+            SocketEvent *event = new SocketEvent;
+            assert (p->last_activity);
+            yaz_log (m_log, "putEvent timeout fd=%d, now = %ld last_activity=%ld timeout=%d",
+                     p->fd, now, p->last_activity, p->timeout);
+            p->last_activity = now;
+            event->observer = p->observer;
+            event->event = SOCKET_OBSERVE_TIMEOUT;
+            putEvent (event);
+            no_put_events++;
+
+        }
+    }
+    SocketEvent *event = getEvent();
+    if (event)
+    {
+        event->observer->socketNotify(event->event);
+        delete event;
+    }
+    else
+    {
+        if (no_lost_observers == 0)
+        {
+            // bug #2035
+            yaz_log(YLOG_WARN, "unhandled socket event. yaz_poll returned %d",
+                    res);
+            yaz_log(YLOG_WARN, "no_put_events=%d no_fds=%d i=%d timeout=%d",
+                    no_put_events, no_fds, i, timeout);
+        }
+    }
+}
+
 int SocketManager::processEvent()
 {
     SocketEntry *p;
@@ -118,38 +207,26 @@ int SocketManager::processEvent()
         return 1;
     }
 
-    fd_set in, out, except;
     int res;
-    int max = 0;
-    int no = 0;
-
-    FD_ZERO(&in);
-    FD_ZERO(&out);
-    FD_ZERO(&except);
-
     time_t now = time(0);
+    int i;
+    int no_fds = 0;
     for (p = m_observers; p; p = p->next)
+        no_fds++;
+
+    if (!no_fds)
+        return 0;
+    struct yaz_poll_fd *fds = new yaz_poll_fd [no_fds];
+    for (i = 0, p = m_observers; p; p = p->next, i++)
     {
-        int fd = p->fd;
-        if (p->mask)
-            no++;
+        fds[i].fd = p->fd;
+        int input_mask = 0;
         if (p->mask & SOCKET_OBSERVE_READ)
-        {
-            yaz_log (m_log, "SocketManager::select fd=%d read", fd);
-            FD_SET(fd, &in);
-        }
+            input_mask += yaz_poll_read;
         if (p->mask & SOCKET_OBSERVE_WRITE)
-        {
-            yaz_log (m_log, "SocketManager::select fd=%d write", fd);
-            FD_SET(fd, &out);
-        }
+            input_mask += yaz_poll_write;
         if (p->mask & SOCKET_OBSERVE_EXCEPT)
-        {
-            yaz_log (m_log, "SocketManager::select fd=%d except", fd);
-            FD_SET(fd, &except);
-        }
-        if (fd > max)
-            max = fd;
+            input_mask += yaz_poll_except;
         if (p->timeout > 0 ||
             (p->timeout == 0 && (p->mask & SOCKET_OBSERVE_WRITE) == 0))
         {
@@ -164,82 +241,31 @@ int SocketManager::processEvent()
             if (timeout == -1 || timeout_this < timeout)
                 timeout = timeout_this;
             p->timeout_this = timeout_this;
-            yaz_log (m_log, "SocketManager::select timeout_this=%d", 
+            yaz_log (m_log, "SocketManager::select timeout_this=%d",
                      p->timeout_this);
         }
         else
             p->timeout_this = -1;
-    }
-    if (!no)
-    {
-        yaz_log (m_log, "no pending events return 0");
-        if (!m_observers)
-            yaz_log (m_log, "no observers");
-        return 0;
+        fds[i].input_mask = (enum yaz_poll_mask) input_mask;
     }
 
-    struct timeval to;
-    to.tv_sec = timeout;
-    to.tv_usec = 0;
-    
-    yaz_log (m_log, "SocketManager::select begin no=%d timeout=%d",
-             no, timeout);
     int pass = 0;
-    while ((res = select(max + 1, &in, &out, &except,
-                         timeout== -1 ? 0 : &to)) < 0)
-        if (errno != EINTR)
-        {
-            yaz_log(YLOG_ERRNO|YLOG_WARN, "select");
-            yaz_log(YLOG_WARN, "errno=%d max=%d timeout=%d",
-                             errno, max, timeout);
-            if (++pass > 10)
-                return -1;
-        }
-    yaz_log(m_log, "select returned res=%d", res);
-    now = time(0);
-    for (p = m_observers; p; p = p->next)
+    while ((res = yaz_poll(fds, no_fds, timeout, 0)) < 0 && pass < 10)
     {
-        int fd = p->fd;
-        int mask = 0;
-        if (FD_ISSET(fd, &in))
-            mask |= SOCKET_OBSERVE_READ;
-
-        if (FD_ISSET(fd, &out))
-            mask |= SOCKET_OBSERVE_WRITE;
-
-        if (FD_ISSET(fd, &except))
-            mask |= SOCKET_OBSERVE_EXCEPT;
-        
-        if (mask)
+        if (errno == EINTR)
         {
-            SocketEvent *event = new SocketEvent;
-            p->last_activity = now;
-            event->observer = p->observer;
-            event->event = mask;
-            putEvent (event);
-
-            yaz_log (m_log, "putEvent I/O mask=%d", mask);
-        }
-        else if (res == 0 && p->timeout_this == timeout)
-        {
-            SocketEvent *event = new SocketEvent;
-            assert (p->last_activity);
-            yaz_log (m_log, "putEvent timeout fd=%d, now = %ld last_activity=%ld timeout=%d",
-                     p->fd, now, p->last_activity, p->timeout);
-            p->last_activity = now;
-            event->observer = p->observer;
-            event->event = SOCKET_OBSERVE_TIMEOUT;
-            putEvent (event);
+            delete [] fds;
+            return 1;
         }
+        yaz_log(YLOG_ERRNO|YLOG_WARN, "yaz_poll");
+        yaz_log(YLOG_WARN, "errno=%d timeout=%d", errno, timeout);
     }
-    if ((event = getEvent()))
-    {
-        event->observer->socketNotify(event->event);
-        delete event;
-        return 1;
-    }
-    yaz_log(YLOG_WARN, "unhandled event in processEvent res=%d", res);
-    return 1;
+
+    if (res >= 0)
+        inspect_poll_result(res, fds, no_fds, timeout);
+
+    delete [] fds;
+    return res >= 0 ? 1 : -1;
 }
 
 
@@ -319,6 +345,7 @@ SocketManager::~SocketManager()
 /*
  * Local variables:
  * c-basic-offset: 4
+ * c-file-style: "Stroustrup"
  * indent-tabs-mode: nil
  * End:
  * vim: shiftwidth=4 tabstop=8 expandtab