dol: initial dol commit
[jump.git] / dol / src / dol / visitor / hdsd / scd / scd_sock_poller.cpp
diff --git a/dol/src/dol/visitor/hdsd/scd/scd_sock_poller.cpp b/dol/src/dol/visitor/hdsd/scd/scd_sock_poller.cpp
new file mode 100644 (file)
index 0000000..1cff374
--- /dev/null
@@ -0,0 +1,201 @@
+#include "scd_sock_poller.h"
+
+#include <algorithm>
+#include <errno.h>
+#include <string>
+#include <string.h>
+
+#include "scd_exception.h"
+#include "scd_logging.h"
+
+
+bool scd_sock_poller::register_handler(scd_sock_ev_handler_if& handler,
+        sock_ev events)
+{
+    // can not register the same handler twice
+    if (_handler_exists(handler))
+    {
+        scd_warn("socket handler already registered while registering");
+        return false;
+    }
+    
+    // register handler
+    _handlers.push_back(&handler);
+
+    // register socket and events
+    struct pollfd fd;
+    fd.fd = handler.get_sock()._socket;
+    fd.events = events;
+    _events.push_back(fd);
+    return true;
+
+} // register_handler()
+
+
+bool scd_sock_poller::remove_handler(const scd_sock_ev_handler_if &handler)
+{
+    int idx = _get_index(handler);
+    
+    // check if handler was found
+    if (idx == -1)
+    {
+        scd_warn("socket handler not registered while removing poll handler");
+        return false;
+    }
+
+    // remove events and handler from vectors
+    _events.erase(_events.begin() + idx);
+    _handlers.erase(_handlers.begin() + idx);
+
+    return true;
+
+} // remove_handler()
+
+
+bool scd_sock_poller::set_ev(const scd_sock_ev_handler_if &handler,
+        sock_ev events)
+{
+    int idx = _get_index(handler);
+
+    if (idx == -1)
+    {
+        scd_warn("socket handler not registered while setting poll events");
+        return false;
+    }
+
+    _events[idx].events = events;
+
+    return true;
+} // set_ev()
+
+
+bool scd_sock_poller::get_ev(const scd_sock_ev_handler_if &handler,
+        sock_ev &events) const
+{
+    int idx = _get_index(handler);
+
+    if (idx == -1)
+    {
+        scd_warn("socket handler not registered while getting poll events");
+        return false;
+    }
+
+    events = _events[idx].events;
+
+    return true;
+
+} // get_ev()
+
+
+bool scd_sock_poller::wait(int ms)
+{
+    int ret = _poll(ms);
+    if (ret > 0)
+        return true;
+    else
+        return false;
+}
+
+
+bool scd_sock_poller::process()
+{
+    int ret = _poll(0);
+
+    if (ret != 0) // events occured
+    {
+        _callback();
+        return true;
+    }
+    else
+        return false;
+
+} // process()
+
+
+void scd_sock_poller::wait_process()
+{
+    _poll(-1);
+    _callback();
+
+} // wait_process()
+
+
+bool scd_sock_poller::_handler_exists(const scd_sock_ev_handler_if &handler)
+    const
+{
+    std::vector<scd_sock_ev_handler_if*>::const_iterator iter;
+
+    iter = std::find(_handlers.begin(), _handlers.end(), &handler);
+
+    if (iter == _handlers.end())
+        return false;
+    else
+        return true;
+
+} // _handler_exists()
+
+
+int scd_sock_poller::_get_index(const scd_sock_ev_handler_if &handler) const
+{
+    std::vector<scd_sock_ev_handler_if*>::const_iterator iter;
+
+    iter = std::find(_handlers.begin(), _handlers.end(), &handler);
+
+    if (iter == _handlers.end())
+    {
+        // handler not found
+        return -1;
+    }
+    else
+    {
+        // return index (random access iterator)
+        return iter - _handlers.begin();
+    }
+
+} // _get_index()
+
+
+int scd_sock_poller::_poll(int ms)
+{
+    int ret;
+
+    if (ms < 0 && _events.size() == 0)
+    {
+        scd_debug("immediately returning form infinite poll: no events to watch");
+        return 0;
+    }
+
+    do
+    {
+        ret = poll(&_events[0], _events.size(), ms);
+        if (ret == -1 && errno != EINTR)
+        {
+            std::string error("poll(): ");
+            error += std::string(strerror(errno));
+            throw scd_exception(error);
+        }
+    }
+    while (ret == -1 && errno == EINTR);
+
+    return ret;
+
+} // _poll()
+
+
+void scd_sock_poller::_callback()
+{
+    /* called handlers might remove themselves. as the order
+     * should not break we operate on copies here */
+    std::vector<pollfd> events_cpy = _events;
+    std::vector<scd_sock_ev_handler_if*> handlers_cpy = _handlers;
+
+    // for all handlers
+    for (int i=0; i<events_cpy.size(); i++)
+    {
+        if (events_cpy[i].events & events_cpy[i].revents)
+        {
+            // this event occured => callback handler
+            handlers_cpy[i]->handle_sock_ev(events_cpy[i].revents);
+        }
+    } // for all events
+} // _callback()