diff options
Diffstat (limited to 'vdr-vdrmanager/select.cpp')
-rw-r--r-- | vdr-vdrmanager/select.cpp | 205 |
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; +} |