mirror of
https://projects.vdr-developer.org/git/vdr-plugin-streamdev.git
synced 2023-10-10 19:16:51 +02:00
afe255aa0b
with the "red" key. The former main menu action of suspending live TV moved to the "blue" key. Squashed commit of the following: commit 7175d7de91b637eb057831b5c27af78d3870f146 Author: Frank Schmirler <vdr@schmirler.de> Date: Sun Nov 27 11:51:26 2011 +0100 Updated README commit 94aef85adc9c2922205145550ff00e59c694e36d Author: Frank Schmirler <vdr@schmirler.de> Date: Sun Nov 27 11:32:16 2011 +0100 Moved "closing connection" log message to overload of cTBSocket::Close() in cServerConnection. commit 9b91301d943cfbec5208419704cfece84267223d Author: Frank Schmirler <vdr@schmirler.de> Date: Fri Nov 25 00:24:37 2011 +0100 Don't keep a pointer to the connection in components MulticastGroup structure as the connection may now be deleted from outside via menu. commit 7347e24123ec0b852091ec035cabce0e10278a72 Author: Frank Schmirler <vdr@schmirler.de> Date: Thu Nov 24 23:45:59 2011 +0100 Fixed missing Display() call after disconnecting a client. commit c652e8fa8141d7e323cbdbbc0a662244a5a84955 Author: Frank Schmirler <vdr@schmirler.de> Date: Tue Nov 22 01:15:09 2011 +0100 Added server menu with list of clients. Connections can be terminated with the "red" key. The former main menu action of suspending live TV moved to the "blue" key.
185 lines
4.3 KiB
C
185 lines
4.3 KiB
C
/*
|
|
* $Id: server.c,v 1.10 2009/02/13 10:39:22 schmirl Exp $
|
|
*/
|
|
|
|
#include "server/server.h"
|
|
#include "server/componentVTP.h"
|
|
#include "server/componentHTTP.h"
|
|
#include "server/componentIGMP.h"
|
|
#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;
|
|
|
|
cStreamdevServer *cStreamdevServer::m_Instance = NULL;
|
|
cList<cServerComponent> cStreamdevServer::m_Servers;
|
|
cList<cServerConnection> cStreamdevServer::m_Clients;
|
|
|
|
cStreamdevServer::cStreamdevServer(void):
|
|
cThread("streamdev server")
|
|
{
|
|
Start();
|
|
}
|
|
|
|
cStreamdevServer::~cStreamdevServer()
|
|
{
|
|
Stop();
|
|
}
|
|
|
|
void cStreamdevServer::Initialize(void)
|
|
{
|
|
if (m_Instance == NULL) {
|
|
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);
|
|
}
|
|
|
|
m_Instance = new cStreamdevServer;
|
|
}
|
|
}
|
|
|
|
void cStreamdevServer::Destruct(void)
|
|
{
|
|
DELETENULL(m_Instance);
|
|
}
|
|
|
|
void cStreamdevServer::Stop(void)
|
|
{
|
|
if (Running())
|
|
Cancel(3);
|
|
}
|
|
|
|
void cStreamdevServer::Register(cServerComponent *Server)
|
|
{
|
|
m_Servers.Add(Server);
|
|
}
|
|
|
|
void cStreamdevServer::Action(void)
|
|
{
|
|
/* Initialize Server components, deleting those that failed */
|
|
for (cServerComponent *c = m_Servers.First(); c;) {
|
|
cServerComponent *next = m_Servers.Next(c);
|
|
if (!c->Initialize())
|
|
m_Servers.Del(c);
|
|
c = next;
|
|
}
|
|
|
|
if (m_Servers.Count() == 0) {
|
|
esyslog("ERROR: no streamdev server activated, exiting");
|
|
Cancel(-1);
|
|
}
|
|
|
|
cTBSelect select;
|
|
while (Running()) {
|
|
select.Clear();
|
|
|
|
/* Ask all Server components to register to the selector */
|
|
for (cServerComponent *c = m_Servers.First(); c; c = m_Servers.Next(c))
|
|
select.Add(c->Socket(), false);
|
|
|
|
/* Ask all Client connections to register to the selector */
|
|
for (cServerConnection *s = m_Clients.First(); s; s = m_Clients.Next(s))
|
|
{
|
|
select.Add(s->Socket(), false);
|
|
if (s->HasData())
|
|
select.Add(s->Socket(), true);
|
|
}
|
|
|
|
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");
|
|
break;
|
|
}
|
|
|
|
/* Ask all Server components to act on signalled sockets */
|
|
for (cServerComponent *c = m_Servers.First(); c; c = m_Servers.Next(c)){
|
|
if (sel && select.CanRead(c->Socket())) {
|
|
cServerConnection *client = c->Accept();
|
|
if (!client)
|
|
continue;
|
|
Lock();
|
|
m_Clients.Add(client);
|
|
Unlock();
|
|
|
|
if (m_Clients.Count() > StreamdevServerSetup.MaxClients) {
|
|
esyslog("streamdev: too many clients, rejecting %s:%d",
|
|
client->RemoteIp().c_str(), client->RemotePort());
|
|
client->Reject();
|
|
} else if (!client->CanAuthenticate() && !StreamdevHosts.Acceptable(client->RemoteIpAddr())) {
|
|
esyslog("streamdev: client %s:%d not allowed to connect",
|
|
client->RemoteIp().c_str(), client->RemotePort());
|
|
client->Reject();
|
|
} else
|
|
client->Welcome();
|
|
}
|
|
}
|
|
|
|
/* Ask all Client connections to act on signalled sockets */
|
|
for (cServerConnection *s = m_Clients.First(); s;) {
|
|
bool result = true;
|
|
|
|
if (sel && select.CanWrite(s->Socket()))
|
|
result = s->Write();
|
|
|
|
if (sel && result && select.CanRead(s->Socket()))
|
|
result = s->Read();
|
|
|
|
result &= !s->Abort();
|
|
|
|
cServerConnection *next = m_Clients.Next(s);
|
|
if (!result) {
|
|
if (s->IsOpen())
|
|
s->Close();
|
|
Lock();
|
|
m_Clients.Del(s);
|
|
Unlock();
|
|
}
|
|
s = next;
|
|
}
|
|
}
|
|
|
|
Lock();
|
|
while (m_Clients.Count() > 0) {
|
|
cServerConnection *s = m_Clients.First();
|
|
s->Close();
|
|
m_Clients.Del(s);
|
|
}
|
|
Unlock();
|
|
|
|
while (m_Servers.Count() > 0) {
|
|
cServerComponent *c = m_Servers.First();
|
|
c->Destruct();
|
|
m_Servers.Del(c);
|
|
}
|
|
}
|
|
|
|
const cList<cServerConnection>& cStreamdevServer::Clients(cThreadLock& Lock)
|
|
{
|
|
Lock.Lock(m_Instance);
|
|
return m_Clients;
|
|
}
|