sock_man_t API complete
authorAdam Dickmeiss <adam@indexdata.dk>
Mon, 4 Jan 2010 21:07:26 +0000 (22:07 +0100)
committerAdam Dickmeiss <adam@indexdata.dk>
Mon, 4 Jan 2010 21:07:26 +0000 (22:07 +0100)
include/yaz/sock_man.h
src/Makefile.am
src/nanohttp.c
src/sock_man.c

index 75bc841..0efc9b1 100644 (file)
@@ -47,11 +47,24 @@ YAZ_EXPORT
 void yaz_sock_man_destroy(yaz_sock_man_t man);
 
 YAZ_EXPORT
-yaz_sock_chan_t yaz_sock_chan_new(yaz_sock_man_t srv, int fd, void *data);
+yaz_sock_chan_t yaz_sock_chan_new(yaz_sock_man_t srv, int fd, void *data,
+                                  unsigned mask);
 
 YAZ_EXPORT
 void yaz_sock_chan_destroy(yaz_sock_man_t srv, yaz_sock_chan_t p);
 
+YAZ_EXPORT
+void yaz_sock_chan_set_mask(yaz_sock_chan_t chan, unsigned mask);
+
+YAZ_EXPORT
+void yaz_sock_chan_set_max_idle(yaz_sock_chan_t chan, int max_idle);
+
+YAZ_EXPORT
+unsigned yaz_sock_get_mask(yaz_sock_chan_t chan);
+
+YAZ_EXPORT
+void *yaz_sock_chan_get_data(yaz_sock_chan_t chan);
+
 YAZ_END_CDECL
 
 #endif
index 0eefdf0..96ad379 100644 (file)
@@ -103,7 +103,7 @@ libyaz_la_SOURCES=version.c options.c log.c \
   copy_types.c match_glob.c poll.c daemon.c \
   iconv_encode_marc8.c iconv_encode_iso_8859_1.c iconv_encode_wchar.c \
   iconv_decode_marc8.c iconv_decode_iso5426.c iconv_decode_danmarc.c sc.c \
-  sock_man.c
+  sock_man.c nanohttp.c
 
 libyaz_la_LDFLAGS=-version-info $(YAZ_VERSION_INFO)
 
index 3c0e945..259ffb4 100644 (file)
@@ -11,7 +11,7 @@
 #include <yaz/comstack.h>
 #include <yaz/nmem.h>
 #include <yaz/log.h>
-#include <yaz/poll.h>
+#include <yaz/sock_man.h>
 #include <assert.h>
 
 typedef struct yaz_nano_srv_s *yaz_nano_srv_t;
@@ -29,7 +29,7 @@ struct yaz_nano_srv_s {
     COMSTACK *cs_listeners;
     size_t num_listeners;
     NMEM nmem;
-    struct yaz_poll_fd *fds;
+    yaz_sock_man_t sock_man;
 };
 
 void yaz_nano_srv_destroy(yaz_nano_srv_t p)
@@ -40,6 +40,7 @@ void yaz_nano_srv_destroy(yaz_nano_srv_t p)
         for (i = 0; i < p->num_listeners; i++)
             if (p->cs_listeners[i])
                 cs_close(p->cs_listeners[i]);
+        yaz_sock_man_destroy(p->sock_man);
         nmem_destroy(p->nmem);
     }
 }
@@ -52,8 +53,6 @@ yaz_nano_srv_t yaz_nano_srv_create(const char **listeners_str)
     for (i = 0; listeners_str[i]; i++)
         ;
     p->nmem = nmem;
-    p->chan_list = 0;
-    p->free_list = 0;
     p->num_listeners = i;
     p->cs_listeners = 
         nmem_malloc(nmem, p->num_listeners * sizeof(*p->cs_listeners));
@@ -82,6 +81,8 @@ yaz_nano_srv_t yaz_nano_srv_create(const char **listeners_str)
                 p->cs_listeners[i] = l; /* success */
         }
     }
+    p->sock_man = yaz_sock_man_new();
+
     /* check if all are OK */
     for (i = 0; i < p->num_listeners; i++)
         if (!p->cs_listeners[i])
@@ -92,10 +93,11 @@ yaz_nano_srv_t yaz_nano_srv_create(const char **listeners_str)
 
     for (i = 0; i < p->num_listeners; i++)
     {
-        struct socket_chan *chan = 
-            socket_chan_new(p, cs_fileno(p->cs_listeners[i]),
-                p->cs_listeners + i);
-        socket_chan_set_mask(chan, yaz_poll_read | yaz_poll_except);
+        yaz_sock_chan_t chan;
+
+        chan = yaz_sock_chan_new(p->sock_man, cs_fileno(p->cs_listeners[i]),
+                                 p->cs_listeners + i,
+                                 yaz_poll_read | yaz_poll_except);
     }    
     return p;
 }
@@ -122,40 +124,6 @@ int yaz_nano_pkg_listener_id(yaz_nano_pkg_t pkg)
 
 yaz_nano_pkg_t yaz_nano_srv_get_pkg(yaz_nano_srv_t p)
 {
-    size_t i;
-    int ret;
-    int num_fds = 0;
-    struct yaz_poll_fd *fds;
-    struct socket_chan *chan = p->chan_list;
-    for (chan = p->chan_list; chan; chan = chan->next)
-        num_fds++;
-    fds = xmalloc(num_fds * sizeof(*fds));
-    for (i = 0, chan = p->chan_list; chan; chan = chan->next)
-    {
-        fds[i].input_mask = chan->mask;
-        fds[i].fd = chan->fd;
-        fds[i].client_data = chan;
-    }
-    ret = yaz_poll(fds, num_fds, 0, 0);
-    if (ret == -1)
-    {
-        yaz_log(YLOG_WARN, "yaz_poll error");
-    }
-    else if (ret == 0)
-    {
-        yaz_log(YLOG_LOG, "yaz_poll timeout");
-    }
-    else
-    {
-        for (i = 0, chan = p->chan_list; chan; chan = chan->next)
-        {
-            if (fds[i].output_mask)
-            {
-                yaz_log(YLOG_LOG, "event on chan=%p", chan);
-            }
-        }
-    }
-    xfree(fds);
     return 0;
 }
 
index 725a901..90e6810 100644 (file)
@@ -3,14 +3,20 @@
 #include <yaz/nmem.h>
 #include <assert.h>
 #include <sys/epoll.h>
+#include <unistd.h>
 
 struct yaz_sock_man_s {
     yaz_sock_chan_t chan_list;
     yaz_sock_chan_t free_list;
+    yaz_sock_chan_t timeout_list;
     NMEM nmem;
     int epoll_handle;
     int maxevents;
-    yaz_sock_chan_t *events;
+    int event_no;
+    int event_ret;
+    int timeout;
+    int rescan;
+    struct epoll_event *events;
 };
 
 struct yaz_sock_chan_s {
@@ -18,7 +24,10 @@ struct yaz_sock_chan_s {
     yaz_sock_chan_t prev;
     int fd;
     unsigned mask;
+    unsigned output_mask;
+    int max_idle;
     void *data;
+    yaz_sock_man_t man;
 };
 
 yaz_sock_man_t yaz_sock_man_new(void)
@@ -28,8 +37,13 @@ yaz_sock_man_t yaz_sock_man_new(void)
     man->nmem = nmem;
     man->chan_list = 0;
     man->free_list = 0;
+    man->timeout_list = 0;
     man->epoll_handle = epoll_create(100);
     man->maxevents = 30;
+    man->event_no = 0;
+    man->event_ret = 0;
+    man->timeout = 0;
+    man->rescan = 0;
     man->events = nmem_malloc(nmem, man->maxevents * sizeof(*man->events));
     if (man->epoll_handle == -1)
     {
@@ -50,7 +64,25 @@ void yaz_sock_man_destroy(yaz_sock_man_t man)
     }
 }
 
-yaz_sock_chan_t yaz_sock_chan_new(yaz_sock_man_t srv, int fd, void *data)
+static void poll_ctl(int op, yaz_sock_chan_t p)
+{
+    struct epoll_event event;
+
+    event.events = 0;
+    if (p->mask & yaz_poll_read)
+        event.events |= EPOLLIN;
+    if (p->mask & yaz_poll_write)
+        event.events |= EPOLLOUT;
+    if (p->mask & yaz_poll_except)
+        event.events |= EPOLLERR;
+
+    event.data.ptr = p;
+    epoll_ctl(p->man->epoll_handle, op, p->fd, &event);
+
+}
+
+yaz_sock_chan_t yaz_sock_chan_new(yaz_sock_man_t srv, int fd, void *data,
+                                  unsigned mask)
 {
     yaz_sock_chan_t p;
     if (srv->free_list)
@@ -69,9 +101,27 @@ yaz_sock_chan_t yaz_sock_chan_new(yaz_sock_man_t srv, int fd, void *data)
     p->fd = fd;
     p->mask = 0;
     p->data = data;
+    p->max_idle = 0;
+    p->man = srv;
+
+    poll_ctl(EPOLL_CTL_ADD, p);
     return p;
 }
 
+static void rescan_timeout(yaz_sock_man_t man)
+{
+    if (man->rescan)
+    {
+        int timeout = 0;
+        yaz_sock_chan_t p;
+        for (p = man->chan_list; p; p = p->next)
+            if (p->max_idle && (timeout == 0 || p->max_idle < timeout))
+                timeout = p->max_idle;
+        man->timeout = timeout;
+        man->rescan = 0;
+    }
+}
+
 void yaz_sock_chan_destroy(yaz_sock_man_t srv, yaz_sock_chan_t p)
 {
     if (p->prev)
@@ -84,20 +134,88 @@ void yaz_sock_chan_destroy(yaz_sock_man_t srv, yaz_sock_chan_t p)
 
     if (p->next)
         p->next->prev = p->prev;
-    
+
+    poll_ctl(EPOLL_CTL_DEL, p);
+
     p->next = srv->free_list;
     p->prev = 0;
     srv->free_list = p;
+
+    srv->rescan = 1;
 }
 
 yaz_sock_chan_t yaz_sock_man_wait(yaz_sock_man_t man)
 {
-    return 0;
+    struct epoll_event *ev;
+    yaz_sock_chan_t chan = 0;
+
+    if (man->timeout_list)
+    { /* possibly timeout events not returned */
+        for (chan = man->timeout_list; chan; chan = chan->next)
+            if (chan->max_idle == man->timeout)
+                break;
+        if (chan)
+        {
+            man->timeout_list = chan->next;
+            chan->output_mask = yaz_poll_timeout;
+            return chan;
+        }
+        man->timeout_list = 0; /* no more timeout events */
+    }
+    assert(man->timeout_list = 0);
+    assert(man->event_no <= man->event_ret);
+    if (man->event_no == man->event_ret)
+    { /* must wait again */
+        rescan_timeout(man);
+        man->event_no = 0;
+        man->event_ret = epoll_wait(man->epoll_handle, man->events,
+                                    man->maxevents, man->timeout);
+        if (man->event_ret == 0)
+        {
+            /* timeout */
+            for (chan = man->chan_list; chan; chan = chan->next)
+                if (chan->max_idle == man->timeout)
+                    break;
+            assert(chan); /* there must be one chan in a timeout state */
+            man->timeout_list = chan->next;
+            chan->output_mask = yaz_poll_timeout;
+            return chan;
+        }
+        else if (man->event_ret < 0)
+        {
+            /* error */
+            return 0;
+        }
+    }
+    ev = man->events + man->event_no;
+    chan = ev->data.ptr;
+    chan->output_mask = 0;
+    if (ev->events & EPOLLIN)
+        chan->output_mask |= yaz_poll_read;
+    if (ev->events & EPOLLOUT)
+        chan->output_mask |= yaz_poll_write;
+    if (ev->events & EPOLLERR)
+        chan->output_mask |= yaz_poll_except;
+    man->event_no++;
+    return chan;
 }
 
 void yaz_sock_chan_set_mask(yaz_sock_chan_t chan, unsigned mask)
 {
-    chan->mask = mask;
+    if (chan->mask != mask)
+    {
+        chan->mask = mask;
+        poll_ctl(EPOLL_CTL_MOD, chan);
+    }
+}
+
+void yaz_sock_chan_set_max_idle(yaz_sock_chan_t chan, int max_idle)
+{
+    if (chan->max_idle != max_idle)
+    {
+        chan->max_idle = max_idle;
+        chan->man->rescan = 1;
+    }
 }
 
 unsigned yaz_sock_get_mask(yaz_sock_chan_t chan)