vdr-plugin-streamdev/server/server.c

189 lines
4.4 KiB
C
Raw Permalink Normal View History

2004-12-30 23:43:55 +01:00
/*
* $Id: server.c,v 1.10 2009/02/13 10:39:22 schmirl Exp $
2004-12-30 23:43:55 +01:00
*/
#include "server/server.h"
#include "server/componentVTP.h"
#include "server/componentHTTP.h"
#include "server/componentIGMP.h"
2004-12-30 23:43:55 +01:00
#include "server/setup.h"
#include <vdr/tools.h>
#include <tools/select.h>
#include <string.h>
#include <errno.h>
cSVDRPhosts StreamdevHosts;
char *opt_auth = NULL;
char *opt_remux = NULL;
2004-12-30 23:43:55 +01:00
2005-05-09 22:22:29 +02:00
cStreamdevServer *cStreamdevServer::m_Instance = NULL;
cList<cServerComponent> cStreamdevServer::m_Servers;
cList<cServerConnection> cStreamdevServer::m_Clients;
2004-12-30 23:43:55 +01:00
2005-05-09 22:22:29 +02:00
cStreamdevServer::cStreamdevServer(void):
cThread("streamdev server")
2004-12-30 23:43:55 +01:00
{
2005-05-09 22:22:29 +02:00
Start();
2004-12-30 23:43:55 +01:00
}
2005-05-09 22:22:29 +02:00
cStreamdevServer::~cStreamdevServer()
{
Stop();
2004-12-30 23:43:55 +01:00
}
2005-05-09 22:22:29 +02:00
void cStreamdevServer::Initialize(void)
{
2004-12-30 23:43:55 +01:00
if (m_Instance == NULL) {
2005-05-09 22:22:29 +02:00
if (StreamdevServerSetup.StartVTPServer) Register(new cComponentVTP);
if (StreamdevServerSetup.StartHTTPServer) Register(new cComponentHTTP);
if (StreamdevServerSetup.StartIGMPServer) {
if (strcmp(StreamdevServerSetup.IGMPBindIP, "0.0.0.0") == 0)
esyslog("streamdev-server: Not starting IGMP. IGMP must be bound to a local IP");
else
Register(new cComponentIGMP);
}
2005-05-09 22:22:29 +02:00
2004-12-30 23:43:55 +01:00
m_Instance = new cStreamdevServer;
}
}
2005-05-09 22:22:29 +02:00
void cStreamdevServer::Destruct(void)
{
DELETENULL(m_Instance);
2004-12-30 23:43:55 +01:00
}
2005-05-09 22:22:29 +02:00
void cStreamdevServer::Stop(void)
{
if (Running())
2005-05-09 22:22:29 +02:00
Cancel(3);
2004-12-30 23:43:55 +01:00
}
2005-05-09 22:22:29 +02:00
void cStreamdevServer::Register(cServerComponent *Server)
{
2004-12-30 23:43:55 +01:00
m_Servers.Add(Server);
}
2005-05-09 22:22:29 +02:00
void cStreamdevServer::Action(void)
{
2004-12-30 23:43:55 +01:00
/* Initialize Server components, deleting those that failed */
for (cServerComponent *c = m_Servers.First(); c;) {
cServerComponent *next = m_Servers.Next(c);
2005-05-09 22:22:29 +02:00
if (!c->Initialize())
2004-12-30 23:43:55 +01:00
m_Servers.Del(c);
c = next;
}
2005-05-09 22:22:29 +02:00
if (m_Servers.Count() == 0) {
esyslog("ERROR: no streamdev server activated, exiting");
Cancel(-1);
2004-12-30 23:43:55 +01:00
}
2005-05-09 22:22:29 +02:00
cTBSelect select;
while (Running()) {
2004-12-30 23:43:55 +01:00
select.Clear();
/* Ask all Server components to register to the selector */
for (cServerComponent *c = m_Servers.First(); c; c = m_Servers.Next(c))
2005-05-09 22:22:29 +02:00
select.Add(c->Socket(), false);
2004-12-30 23:43:55 +01:00
/* Ask all Client connections to register to the selector */
for (cServerConnection *s = m_Clients.First(); s; s = m_Clients.Next(s))
2005-05-09 22:22:29 +02:00
{
select.Add(s->Socket(), false);
if (s->HasData())
select.Add(s->Socket(), true);
}
2004-12-30 23:43:55 +01:00
int sel;
do
{
sel = select.Select(400);
if (sel < 0 && errno == ETIMEDOUT) {
// check for aborted clients
for (cServerConnection *s = m_Clients.First(); s; s = m_Clients.Next(s)) {
if (s->Abort())
sel = 0;
}
}
} while (sel < 0 && errno == ETIMEDOUT && Running());
if (!Running())
break;
if (sel < 0) {
esyslog("fatal error, server exiting: %m");
2005-05-09 22:22:29 +02:00
break;
2004-12-30 23:43:55 +01:00
}
/* Ask all Server components to act on signalled sockets */
2005-05-09 22:22:29 +02:00
for (cServerComponent *c = m_Servers.First(); c; c = m_Servers.Next(c)){
if (sel && select.CanRead(c->Socket())) {
2005-05-09 22:22:29 +02:00
cServerConnection *client = c->Accept();
if (!client)
continue;
Lock();
2004-12-30 23:43:55 +01:00
m_Clients.Add(client);
Unlock();
2004-12-30 23:43:55 +01:00
if (m_Clients.Count() > StreamdevServerSetup.MaxClients) {
2005-05-09 22:22:29 +02:00
esyslog("streamdev: too many clients, rejecting %s:%d",
2005-02-08 18:22:35 +01:00
client->RemoteIp().c_str(), client->RemotePort());
2004-12-30 23:43:55 +01:00
client->Reject();
} else if (!client->CanAuthenticate() && !StreamdevHosts.Acceptable(client->RemoteIpAddr())) {
2005-05-09 22:22:29 +02:00
esyslog("streamdev: client %s:%d not allowed to connect",
2005-02-08 18:22:35 +01:00
client->RemoteIp().c_str(), client->RemotePort());
2004-12-30 23:43:55 +01:00
client->Reject();
} else
client->Welcome();
}
}
/* Ask all Client connections to act on signalled sockets */
for (cServerConnection *s = m_Clients.First(); s;) {
2005-05-09 22:22:29 +02:00
bool result = true;
if (sel && select.CanWrite(s->Socket()))
2005-05-09 22:22:29 +02:00
result = s->Write();
if (sel && result && select.CanRead(s->Socket()))
2005-05-09 22:22:29 +02:00
result = s->Read();
result &= !s->Abort();
2005-05-09 22:22:29 +02:00
2004-12-30 23:43:55 +01:00
cServerConnection *next = m_Clients.Next(s);
2005-05-09 22:22:29 +02:00
if (!result) {
if (s->IsOpen())
s->Close();
Lock();
2004-12-30 23:43:55 +01:00
m_Clients.Del(s);
Unlock();
2004-12-30 23:43:55 +01:00
}
s = next;
}
}
Lock();
2005-05-09 22:22:29 +02:00
while (m_Clients.Count() > 0) {
cServerConnection *s = m_Clients.First();
s->Close();
m_Clients.Del(s);
2004-12-30 23:43:55 +01:00
}
Unlock();
2004-12-30 23:43:55 +01:00
2005-05-09 22:22:29 +02:00
while (m_Servers.Count() > 0) {
cServerComponent *c = m_Servers.First();
c->Destruct();
m_Servers.Del(c);
2004-12-30 23:43:55 +01:00
}
}
#if APIVERSNUM >= 20300
cList<cServerConnection>& cStreamdevServer::Clients(cThreadLock& Lock)
#else
const cList<cServerConnection>& cStreamdevServer::Clients(cThreadLock& Lock)
#endif
{
Lock.Lock(m_Instance);
return m_Clients;
}