summaryrefslogtreecommitdiff
path: root/vdr-vdrmanager/select.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'vdr-vdrmanager/select.cpp')
-rw-r--r--vdr-vdrmanager/select.cpp205
1 files changed, 205 insertions, 0 deletions
diff --git a/vdr-vdrmanager/select.cpp b/vdr-vdrmanager/select.cpp
new file mode 100644
index 0000000..1a463b1
--- /dev/null
+++ b/vdr-vdrmanager/select.cpp
@@ -0,0 +1,205 @@
+/*
+ * select
+ */
+
+#include <sys/select.h>
+#include <vdr/plugin.h>
+#include <vdr/timers.h>
+#include "sock.h"
+#include "select.h"
+#include "handler.h"
+#include "helpers.h"
+
+struct node
+{
+ cVdrmanagerClientSocket * socket;
+ node * next;
+};
+
+cSelect::cSelect()
+{
+ serversocket = NULL;
+ clientsockets = NULL;
+ clientsocketcount = 0;
+ handler = new cHandler;
+ pollfds = NULL;
+ stopped = false;
+ nexttimer = 0;
+ shutdown = 0;
+}
+
+cSelect::~cSelect()
+{
+ if (serversocket)
+ delete serversocket;
+
+ while(clientsockets)
+ {
+ node * next = clientsockets->next;
+ delete clientsockets->socket;
+ delete clientsockets;
+ clientsockets = next;
+ }
+
+ if (handler)
+ delete handler;
+
+ if (pollfds)
+ delete pollfds;
+}
+
+void cSelect::SetServerSocket(cVdrmanagerServerSocket * sock)
+{
+ serversocket = sock;
+}
+
+void cSelect::AddClientSocket(cVdrmanagerClientSocket * sock)
+{
+ // remember socket
+ node * newnode = new node;
+ newnode->next = clientsockets;
+ newnode->socket = sock;
+ clientsockets = newnode;
+ clientsocketcount++;
+}
+
+void cSelect::RemoveClientSocket(cVdrmanagerClientSocket * sock)
+{
+ node * curnode = clientsockets;
+ node * lastnode = NULL;
+ while(curnode)
+ {
+ if (curnode->socket == sock)
+ {
+ // unlink node
+ if (lastnode)
+ lastnode->next = curnode->next;
+ else
+ clientsockets = curnode->next;
+
+ // free socket and node
+ delete curnode->socket;
+ delete curnode;
+
+ clientsocketcount--;
+ break;
+ }
+ lastnode = curnode;
+ curnode = curnode->next;
+ }
+
+ if (clientsockets)
+ {
+ curnode = clientsockets;
+ while (curnode)
+ {
+ curnode = curnode->next;
+ }
+ }
+}
+
+cVdrmanagerClientSocket * cSelect::GetClientSocket(int sock)
+{
+ node * curnode = clientsockets;
+ while (curnode)
+ {
+ if (curnode->socket->GetSocket() == sock)
+ return curnode->socket;
+ curnode = curnode->next;
+ }
+
+ return NULL;
+}
+
+bool cSelect::Action()
+{
+ for(;!stopped;)
+ {
+ if (!Poll())
+ return false;
+ }
+
+ return true;
+}
+
+void cSelect::CreatePollfds()
+{
+ // construct pollfd array
+ // we need one pollfd for the eventpipe,
+ // the serversocket and each clientsocket
+ pollfds = new struct pollfd[clientsocketcount+1];
+ pollfds[0].fd = serversocket->GetSocket();
+ pollfds[0].events = POLLIN;
+
+ node * curnode = clientsockets;
+ int i = 1;
+ while (curnode)
+ {
+ pollfds[i].fd = curnode->socket->GetSocket();
+ pollfds[i].events = POLLIN;
+ if (curnode->socket->WritePending())
+ pollfds[i].events |= POLLOUT;
+ pollfds[i++].revents = 0;
+ curnode = curnode->next;
+ }
+}
+
+bool cSelect::Poll()
+{
+ // poll for events
+ CreatePollfds();
+ int rc = poll(pollfds, clientsocketcount+1, -1);
+ if (rc < 0)
+ {
+ LOG_ERROR;
+ delete pollfds;
+ return false;
+ }
+
+ // timeout?
+ if (rc == 0)
+ return true;
+
+ // client requests or outstanding writes
+ for(int i = 1; i < clientsocketcount+1; i++)
+ {
+ cVdrmanagerClientSocket * sock = GetClientSocket(pollfds[i].fd);
+ if (sock)
+ {
+ if (pollfds[i].revents & (POLLIN|POLLHUP))
+ {
+ // client request
+ handler->HandleClientRequest(sock);
+
+ // disconnect?
+ if (sock->Disconnected())
+ {
+ RemoveClientSocket(sock);
+ }
+ }
+ else if (pollfds[i].revents & POLLOUT)
+ {
+ // possibly outstanding writes
+ sock->Flush();
+ }
+ }
+ }
+
+ // new client?
+ if (pollfds[0].revents & POLLIN)
+ {
+ // get client socket
+ cVdrmanagerClientSocket * sock = serversocket->Accept();
+ if (sock)
+ {
+ // Add client socket
+ AddClientSocket(sock);
+ // Send current data
+ handler->HandleNewClient(sock);
+ }
+ }
+
+ delete pollfds;
+
+ return true;
+}