- added TS compatibility mode

This commit is contained in:
lordjaxom 2005-05-09 20:22:29 +00:00
parent 3eec47314d
commit 450c8fd4a7
18 changed files with 1055 additions and 601 deletions

View File

@ -1,5 +1,5 @@
/*
* $Id: common.h,v 1.5 2005/02/11 16:44:14 lordjaxom Exp $
* $Id: common.h,v 1.6 2005/05/09 20:22:29 lordjaxom Exp $
*/
#ifndef VDR_STREAMDEV_COMMON_H
@ -50,9 +50,6 @@ const cChannel *ChannelFromString(const char *String, int *Apid = NULL);
#define BUFOVERTIME 5000
#define BUFOVERCOUNT 100
#define STREAMDEVHOSTS (const char*)AddDirectory(cPlugin::ConfigDirectory(), \
"streamdevhosts.conf")
#define POLLFAIL esyslog("Streamdev: Polling failed: %s", strerror(errno))
#define WRITEFAIL esyslog("Streamdev: Writing failed: %s", strerror(errno))
#define READFAIL esyslog("Streamdev: Reading failed: %s", strerror(errno))

View File

@ -1,50 +1,48 @@
/*
* $Id: component.c,v 1.2 2005/02/08 17:22:35 lordjaxom Exp $
* $Id: component.c,v 1.3 2005/05/09 20:22:29 lordjaxom Exp $
*/
#include "server/component.h"
#include "server/connection.h"
#include <vdr/tools.h>
#include <string.h>
#include <errno.h>
cServerComponent::cServerComponent(const char *Protocol, const char *ListenIp,
uint ListenPort) {
m_Protocol = Protocol;
m_ListenIp = ListenIp;
m_ListenPort = ListenPort;
uint ListenPort):
m_Protocol(Protocol),
m_ListenIp(ListenIp),
m_ListenPort(ListenPort)
{
}
cServerComponent::~cServerComponent() {
cServerComponent::~cServerComponent()
{
}
bool cServerComponent::Init(void) {
bool cServerComponent::Initialize(void)
{
if (!m_Listen.Listen(m_ListenIp, m_ListenPort, 5)) {
esyslog("Streamdev: Couldn't listen (%s) %s:%d: %s", m_Protocol, m_ListenIp,
m_ListenPort, strerror(errno));
esyslog("Streamdev: Couldn't listen (%s) %s:%d: %m",
m_Protocol, m_ListenIp, m_ListenPort);
return false;
}
isyslog("Streamdev: Listening (%s) on port %d", m_Protocol, m_ListenPort);
return true;
}
void cServerComponent::Exit(void) {
void cServerComponent::Destruct(void)
{
m_Listen.Close();
}
cServerConnection *cServerComponent::CanAct(const cTBSelect &Select) {
if (Select.CanRead(m_Listen)) {
cServerConnection *client = NewConnection();
if (client->Accept(m_Listen)) {
isyslog("Streamdev: Accepted new client (%s) %s:%d", m_Protocol,
client->RemoteIp().c_str(), client->RemotePort());
return client;
} else {
esyslog("Streamdev: Couldn't accept (%s): %s", m_Protocol,
strerror(errno));
delete client;
}
cServerConnection *cServerComponent::Accept(void)
{
cServerConnection *client = NewClient();
if (client->Accept(m_Listen)) {
isyslog("Streamdev: Accepted new client (%s) %s:%d", m_Protocol,
client->RemoteIp().c_str(), client->RemotePort());
return client;
} else {
esyslog("Streamdev: Couldn't accept (%s): %m", m_Protocol);
delete client;
}
return NULL;
}

View File

@ -1,5 +1,5 @@
/*
* $Id: component.h,v 1.1 2004/12/30 22:44:18 lordjaxom Exp $
* $Id: component.h,v 1.2 2005/05/09 20:22:29 lordjaxom Exp $
*/
#ifndef VDR_STREAMDEV_SERVERS_COMPONENT_H
@ -22,29 +22,30 @@ private:
const char *m_ListenIp;
uint m_ListenPort;
protected:
/* Returns a new connection object for Accept() */
virtual cServerConnection *NewClient(void) = 0;
public:
cServerComponent(const char *Protocol, const char *ListenIp, uint ListenPort);
virtual ~cServerComponent();
/* Starts listening on the specified Port, override if you want to do things
different */
virtual bool Init(void);
virtual bool Initialize(void);
/* Stops listening, override if you want to do things different */
virtual void Exit(void);
virtual void Destruct(void);
/* Get the listening socket's file number */
virtual int Socket(void) const { return (int)m_Listen; }
/* Adds the listening socket to the Select object */
virtual void AddSelect(cTBSelect &Select) const { Select.Add(m_Listen); }
virtual void Add(cTBSelect &Select) const { Select.Add(m_Listen); }
/* Accepts the connection on a NewConnection() object and calls the
/* Accepts the connection on a NewClient() object and calls the
Welcome() on it, override if you want to do things different */
virtual cServerConnection *CanAct(const cTBSelect &Select);
/* Returns a new connection object for CanAct */
virtual cServerConnection *NewConnection(void) const = 0;
};
class cServerComponents: public cList<cServerComponent> {
virtual cServerConnection *Accept(void);
};
#endif // VDR_STREAMDEV_SERVERS_COMPONENT_H

View File

@ -1,5 +1,5 @@
/*
* $Id: componentHTTP.c,v 1.1 2004/12/30 22:44:19 lordjaxom Exp $
* $Id: componentHTTP.c,v 1.2 2005/05/09 20:22:29 lordjaxom Exp $
*/
#include "server/componentHTTP.h"
@ -8,8 +8,11 @@
cComponentHTTP::cComponentHTTP(void):
cServerComponent("HTTP", StreamdevServerSetup.HTTPBindIP,
StreamdevServerSetup.HTTPServerPort) {
StreamdevServerSetup.HTTPServerPort)
{
}
cComponentHTTP::~cComponentHTTP() {
cServerConnection *cComponentHTTP::NewClient(void)
{
return new cConnectionHTTP;
}

View File

@ -1,26 +1,18 @@
/*
* $Id: componentHTTP.h,v 1.1 2004/12/30 22:44:19 lordjaxom Exp $
* $Id: componentHTTP.h,v 1.2 2005/05/09 20:22:29 lordjaxom Exp $
*/
#ifndef VDR_STREAMDEV_HTTPSERVER_H
#define VDR_STREAMDEV_HTTPSERVER_H
#include "server/component.h"
#include "server/connectionHTTP.h"
#include <tools/socket.h>
#include <tools/select.h>
class cComponentHTTP: public cServerComponent {
protected:
virtual cServerConnection *NewClient(void);
public:
cComponentHTTP(void);
~cComponentHTTP(void);
virtual cServerConnection *NewConnection(void) const;
};
inline cServerConnection *cComponentHTTP::NewConnection(void) const {
return new cConnectionHTTP;
}
#endif // VDR_STREAMDEV_HTTPSERVER_H

View File

@ -1,5 +1,5 @@
/*
* $Id: componentVTP.c,v 1.1 2004/12/30 22:44:19 lordjaxom Exp $
* $Id: componentVTP.c,v 1.2 2005/05/09 20:22:29 lordjaxom Exp $
*/
#include "server/componentVTP.h"
@ -8,8 +8,11 @@
cComponentVTP::cComponentVTP(void):
cServerComponent("VTP", StreamdevServerSetup.VTPBindIP,
StreamdevServerSetup.VTPServerPort) {
StreamdevServerSetup.VTPServerPort)
{
}
cComponentVTP::~cComponentVTP() {
cServerConnection *cComponentVTP::NewClient(void)
{
return new cConnectionVTP;
}

View File

@ -1,29 +1,18 @@
/*
* $Id: componentVTP.h,v 1.1 2004/12/30 22:44:19 lordjaxom Exp $
* $Id: componentVTP.h,v 1.2 2005/05/09 20:22:29 lordjaxom Exp $
*/
#ifndef VDR_STREAMDEV_SERVERS_SERVERVTP_H
#define VDR_STREAMDEV_SERVERS_SERVERVTP_H
#include "server/component.h"
#include "server/connectionVTP.h"
#include <tools/socket.h>
#include <tools/select.h>
class cComponentVTP: public cServerComponent {
private:
cTBSocket m_Listen;
protected:
virtual cServerConnection *NewClient(void);
public:
cComponentVTP(void);
virtual ~cComponentVTP();
virtual cServerConnection *NewConnection(void) const;
};
inline cServerConnection *cComponentVTP::NewConnection(void) const {
return new cConnectionVTP;
}
#endif // VDR_STREAMDEV_SERVERS_SERVERVTP_H

View File

@ -1,5 +1,5 @@
/*
* $Id: connection.c,v 1.3 2005/03/24 21:31:38 lordjaxom Exp $
* $Id: connection.c,v 1.4 2005/05/09 20:22:29 lordjaxom Exp $
*/
#include "server/connection.h"
@ -11,53 +11,79 @@
#include <string.h>
#include <errno.h>
cServerConnection::cServerConnection(const char *Protocol) {
m_RdBytes = 0;
m_WrBytes = 0;
m_WrOffs = 0;
m_DeferClose = false;
m_Protocol = Protocol;
cServerConnection::cServerConnection(const char *Protocol):
m_Protocol(Protocol),
m_DeferClose(false),
m_Pending(false),
m_ReadBytes(0),
m_WriteBytes(0),
m_WriteIndex(0)
{
}
cServerConnection::~cServerConnection() {
cServerConnection::~cServerConnection()
{
}
bool cServerConnection::CanAct(const cTBSelect &Select) {
if (Select.CanRead(*this)) {
int b;
if ((b = Read(m_RdBuf + m_RdBytes, sizeof(m_RdBuf) - m_RdBytes - 1)) < 0) {
esyslog("Streamdev: Read from client (%s) %s:%d failed: %s", m_Protocol,
RemoteIp().c_str(), RemotePort(), strerror(errno));
return false;
}
if (b == 0) {
isyslog("Streamdev: Client (%s) %s:%d closed connection", m_Protocol,
RemoteIp().c_str(), RemotePort());
return false;
}
m_RdBytes += b;
m_RdBuf[m_RdBytes] = '\0';
return ParseBuffer();
bool cServerConnection::Read(void)
{
int b;
if ((b = cTBSocket::Read(m_ReadBuffer + m_ReadBytes,
sizeof(m_ReadBuffer) - m_ReadBytes - 1)) < 0) {
esyslog("ERROR: read from client (%s) %s:%d failed: %m",
m_Protocol, RemoteIp().c_str(), RemotePort());
return false;
}
if (Select.CanWrite(*this)) {
int b;
if ((b = Write(m_WrBuf + m_WrOffs, m_WrBytes - m_WrOffs)) < 0) {
esyslog("Streamdev: Write to client (%s) %s:%d failed: %s", m_Protocol,
RemoteIp().c_str(), RemotePort(), strerror(errno));
return false;
}
m_WrOffs += b;
if (m_WrOffs == m_WrBytes) {
m_WrBytes = 0;
m_WrOffs = 0;
}
if (b == 0) {
isyslog("client (%s) %s:%d has closed connection",
m_Protocol, RemoteIp().c_str(), RemotePort());
return false;
}
if (m_WrBytes == 0) {
m_ReadBytes += b;
m_ReadBuffer[m_ReadBytes] = '\0';
char *end;
bool result = true;
while ((end = strchr(m_ReadBuffer, '\012')) != NULL) {
*end = '\0';
if (end > m_ReadBuffer && *(end - 1) == '\015')
*(end - 1) = '\0';
if (!Command(m_ReadBuffer))
return false;
m_ReadBytes -= ++end - m_ReadBuffer;
if (m_ReadBytes > 0)
memmove(m_ReadBuffer, end, m_ReadBytes);
}
if (m_ReadBytes == sizeof(m_ReadBuffer) - 1) {
esyslog("ERROR: streamdev: input buffer overflow (%s) for %s:%d",
m_Protocol, RemoteIp().c_str(), RemotePort());
return false;
}
return result;
}
bool cServerConnection::Write(void)
{
int b;
if ((b = cTBSocket::Write(m_WriteBuffer + m_WriteIndex,
m_WriteBytes - m_WriteIndex)) < 0) {
esyslog("ERROR: streamdev: write to client (%s) %s:%d failed: %m",
m_Protocol, RemoteIp().c_str(), RemotePort());
return false;
}
m_WriteIndex += b;
if (m_WriteIndex == m_WriteBytes) {
m_WriteIndex = 0;
m_WriteBytes = 0;
if (m_Pending)
Command(NULL);
if (m_DeferClose)
return false;
Flushed();
@ -65,42 +91,33 @@ bool cServerConnection::CanAct(const cTBSelect &Select) {
return true;
}
bool cServerConnection::ParseBuffer(void) {
char *ep;
bool res;
bool cServerConnection::Respond(const char *Message, bool Last, ...)
{
char *buffer;
int length;
va_list ap;
va_start(ap, Last);
length = vasprintf(&buffer, Message, ap);
va_end(ap);
while ((ep = strchr(m_RdBuf, '\012')) != NULL) {
*ep = '\0';
if (ep > m_RdBuf && *(ep-1) == '\015')
*(ep-1) = '\0';
Dprintf("IN: |%s|\n", m_RdBuf);
res = Command(m_RdBuf);
m_RdBytes -= ++ep - m_RdBuf;
if (m_RdBytes > 0)
memmove(m_RdBuf, ep, m_RdBytes);
if (res == false)
return false;
}
return true;
}
bool cServerConnection::Respond(const std::string &Message) {
if (m_WrBytes + Message.size() + 2 > sizeof(m_WrBuf)) {
esyslog("Streamdev: Output buffer overflow (%s) for %s:%d", m_Protocol,
RemoteIp().c_str(), RemotePort());
if (m_WriteBytes + length + 2 > sizeof(m_WriteBuffer)) {
esyslog("ERROR: streamdev: output buffer overflow (%s) for %s:%d",
m_Protocol, RemoteIp().c_str(), RemotePort());
return false;
}
Dprintf("OUT: |%s|\n", Message.c_str());
memcpy(m_WrBuf + m_WrBytes, Message.c_str(), Message.size());
Dprintf("OUT: |%s|\n", buffer);
memcpy(m_WriteBuffer + m_WriteBytes, buffer, length);
free(buffer);
m_WrBytes += Message.size();
m_WrBuf[m_WrBytes++] = '\015';
m_WrBuf[m_WrBytes++] = '\012';
m_WriteBytes += length;
m_WriteBuffer[m_WriteBytes++] = '\015';
m_WriteBuffer[m_WriteBytes++] = '\012';
m_Pending = !Last;
return true;
}
cDevice *cServerConnection::GetDevice(const cChannel *Channel, int Priority) {
cDevice *cServerConnection::GetDevice(const cChannel *Channel, int Priority)
{
cDevice *device = NULL;
/*Dprintf("+ Statistics:\n");

View File

@ -1,13 +1,11 @@
/*
* $Id: connection.h,v 1.2 2005/02/08 17:22:35 lordjaxom Exp $
* $Id: connection.h,v 1.3 2005/05/09 20:22:29 lordjaxom Exp $
*/
#ifndef VDR_STREAMDEV_SERVER_CONNECTION_H
#define VDR_STREAMDEV_SERVER_CONNECTION_H
#include "tools/socket.h"
#include "tools/select.h"
#include "common.h"
class cChannel;
@ -16,18 +14,32 @@ class cDevice;
/* Basic capabilities of a straight text-based protocol, most functions
virtual to support more complicated protocols */
class cServerConnection: public cListObject, public cTBSocket {
class cServerConnection: public cListObject, public cTBSocket
{
private:
char m_RdBuf[8192];
uint m_RdBytes;
char m_WrBuf[8192];
uint m_WrBytes;
uint m_WrOffs;
const char *m_Protocol;
bool m_DeferClose;
bool m_Pending;
bool m_DeferClose;
char m_ReadBuffer[MAXPARSEBUFFER];
uint m_ReadBytes;
char m_WriteBuffer[MAXPARSEBUFFER];
uint m_WriteBytes;
uint m_WriteIndex;
protected:
/* Will be called when a command terminated by a newline has been
received */
virtual bool Command(char *Cmd) = 0;
/* Will put Message into the response queue, which will be sent in the next
server cycle. Note that Message will be line-terminated by Respond.
Only one line at a time may be sent. If there are lines to follow, set
Last to false. Command(NULL) will be called in the next cycle, so you can
post the next line. */
virtual bool Respond(const char *Message, bool Last = true, ...)
__attribute__ ((format (printf, 2, 4)));
public:
/* If you derive, specify a short string such as HTTP for Protocol, which
@ -41,24 +53,21 @@ public:
/* Gets called if the client has been rejected by the core */
virtual void Reject(void) { DeferClose(); }
/* Adds itself to the Select object, if data can be received or if data is
to be sent. Override if necessary */
virtual void AddSelect(cTBSelect &Select) const;
/* Get the client socket's file number */
virtual int Socket(void) const { return (int)*this; }
/* Receives incoming data and calls ParseBuffer on it. Also writes queued
output data if possible. Override if necessary */
virtual bool CanAct(const cTBSelect &Select);
/* Determine if there is data to send or any command pending */
virtual bool HasData(void) const;
/* Called by CanAct(), parses the input buffer for full lines (terminated
either by '\012' or '\015\012') and calls Command on them, if any */
virtual bool ParseBuffer(void);
/* Gets called by server when the socket can accept more data. Writes
the buffer filled up by Respond(). Calls Command(NULL) if there is a
command pending. Returns false in case of an error */
virtual bool Write(void);
/* Will be called when a command terminated by a newline has been received */
virtual bool Command(char *Cmd) = 0;
/* Will put Message into the response queue, which will be sent in the next
server cycle. Note that Message will be line-terminated by Respond */
bool Respond(const std::string &Message);
/* Gets called by server when there is incoming data to read. Calls
Command() for each line. Returns false in case of an error, or if
the connection shall be closed and removed by the server */
virtual bool Read(void);
/* Will make the socket close after sending all queued output data */
void DeferClose(void) { m_DeferClose = true; }
@ -73,15 +82,9 @@ public:
virtual void Attach(void) = 0;
};
class cServerConnections: public cList<cServerConnection> {
};
inline void cServerConnection::AddSelect(cTBSelect &Select) const {
if (m_WrBytes > 0)
Select.Add(*this, true);
if (m_WrBytes == 0 && m_RdBytes < sizeof(m_RdBuf) - 1)
Select.Add(*this, false);
inline bool cServerConnection::HasData(void) const
{
return m_WriteBytes > 0 || m_Pending || m_DeferClose;
}
#endif // VDR_STREAMDEV_SERVER_CONNECTION_H

View File

@ -1,5 +1,5 @@
/*
* $Id: connectionHTTP.c,v 1.8 2005/04/24 16:26:14 lordjaxom Exp $
* $Id: connectionHTTP.c,v 1.9 2005/05/09 20:22:29 lordjaxom Exp $
*/
#include <ctype.h>
@ -45,7 +45,8 @@ bool cConnectionHTTP::Command(char *Cmd)
return false; // ??? shouldn't happen
}
bool cConnectionHTTP::ProcessRequest(void) {
bool cConnectionHTTP::ProcessRequest(void)
{
Dprintf("process\n");
if (m_Request.substr(0, 4) == "GET " && CmdGET(m_Request.substr(4))) {
switch (m_Job) {
@ -71,7 +72,7 @@ bool cConnectionHTTP::ProcessRequest(void) {
if (m_StreamType == stES && (m_Apid != 0 || ISRADIO(m_Channel))) {
return Respond("HTTP/1.0 200 OK")
&& Respond("Content-Type: audio/mpeg")
&& Respond((std::string)"icy-name: " + m_Channel->Name())
&& Respond("icy-name: %s", true, m_Channel->Name())
&& Respond("");
} else {
return Respond("HTTP/1.0 200 OK")
@ -90,7 +91,8 @@ bool cConnectionHTTP::ProcessRequest(void) {
return Respond("HTTP/1.0 400 Bad Request");
}
void cConnectionHTTP::Flushed(void) {
void cConnectionHTTP::Flushed(void)
{
std::string line;
if (m_Status != hsBody)
@ -132,7 +134,7 @@ void cConnectionHTTP::Flushed(void) {
}
line += "</li>";
}
if (!Respond(line))
if (!Respond(line.c_str()))
DeferClose();
m_ListChannel = Channels.Next(m_ListChannel);
break;
@ -145,7 +147,8 @@ void cConnectionHTTP::Flushed(void) {
}
}
bool cConnectionHTTP::CmdGET(const std::string &Opts) {
bool cConnectionHTTP::CmdGET(const std::string &Opts)
{
const char *sp = Opts.c_str(), *ptr = sp, *ep;
const cChannel *chan;
int apid = 0, pos;
@ -193,33 +196,3 @@ bool cConnectionHTTP::CmdGET(const std::string &Opts) {
return true;
}
#if 0
bool cHTTPConnection::Listing(void) {
cChannel *chan;
cTBString line;
Respond(200, "OK");
Respond("Content-Type: text/html");
Respond("");
Respond("<html><head><title>VDR Channel Listing</title></head>");
Respond("<body><ul>");
for (chan = Channels.First(); chan != NULL; chan = Channels.Next(chan)) {
if (chan->GroupSep() && !*chan->Name())
continue;
if (chan->GroupSep())
line.Format("<li>--- %s ---</li>", chan->Name());
else
line.Format("<li><a href=\"http://%s:%d/%s\">%s</a></li>",
(const char*)m_Socket.LocalIp(), StreamdevServerSetup.HTTPServerPort,
chan->GetChannelID().ToString(), chan->Name());
Respond(line);
}
Respond("</ul></body></html>");
m_DeferClose = true;
return true;
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -3,17 +3,31 @@
#include "server/connection.h"
class cDevice;
class cTBSocket;
class cStreamdevLiveStreamer;
class cLSTEHandler;
class cLSTCHandler;
class cLSTTHandler;
class cConnectionVTP: public cServerConnection {
friend class cLSTEHandler;
private:
cTBSocket *m_DataSockets[si_Count];
cTBSocket *m_LiveSocket;
cStreamdevLiveStreamer *m_LiveStreamer;
// Members adopted from SVDRP
char *m_LastCommand;
bool m_NoTSPIDS;
// Members adopted for SVDRP
cRecordings Recordings;
cLSTEHandler *m_LSTEHandler;
cLSTCHandler *m_LSTCHandler;
cLSTTHandler *m_LSTTHandler;
protected:
template<class cHandler>
bool CmdLSTX(cHandler *&Handler, char *Option);
public:
cConnectionVTP(void);
@ -25,7 +39,7 @@ public:
virtual void Detach(void);
virtual void Attach(void);
bool Command(char *Cmd);
virtual bool Command(char *Cmd);
bool CmdCAPS(char *Opts);
bool CmdPROV(char *Opts);
bool CmdPORT(char *Opts);
@ -38,17 +52,21 @@ public:
bool CmdQUIT(char *Opts);
bool CmdSUSP(char *Opts);
// Commands adopted from SVDRP
bool ReplyWrapper(int Code, const char *fmt, ...);
// Thread-safe implementations of SVDRP commands
bool CmdLSTE(char *Opts);
bool CmdLSTR(char *Opts);
bool CmdDELR(char *Opts);
bool CmdLSTC(char *Opts);
bool CmdLSTT(char *Opts);
bool CmdMODT(char *Opts);
bool CmdNEWT(char *Opts);
bool CmdDELT(char *Opts);
bool Respond(int Code, const std::string &Message);
// Commands adopted from SVDRP
bool CmdMODT(const char *Option);
bool CmdNEWT(const char *Option);
bool CmdDELT(const char *Option);
//bool CmdLSTR(char *Opts);
//bool CmdDELR(char *Opts);
bool Respond(int Code, const char *Message, ...)
__attribute__ ((format (printf, 3, 4)));
};
#endif // VDR_STREAMDEV_SERVERS_CONNECTIONVTP_H

View File

@ -1,5 +1,5 @@
/*
* $Id: server.c,v 1.2 2005/02/08 17:22:35 lordjaxom Exp $
* $Id: server.c,v 1.3 2005/05/09 20:22:29 lordjaxom Exp $
*/
#include "server/server.h"
@ -14,102 +14,101 @@
cSVDRPhosts StreamdevHosts;
cStreamdevServer *cStreamdevServer::m_Instance = NULL;
cStreamdevServer *cStreamdevServer::m_Instance = NULL;
cList<cServerComponent> cStreamdevServer::m_Servers;
cList<cServerConnection> cStreamdevServer::m_Clients;
cStreamdevServer::cStreamdevServer(void)
#if VDRVERSNUM >= 10300
: cThread("Streamdev: server")
#endif
cStreamdevServer::cStreamdevServer(void):
cThread("streamdev server"),
m_Active(false)
{
m_Active = false;
StreamdevHosts.Load(AddDirectory(cPlugin::ConfigDirectory(),
"streamdevhosts.conf"), true);
Start();
}
cStreamdevServer::~cStreamdevServer() {
if (m_Active) Stop();
cStreamdevServer::~cStreamdevServer()
{
Stop();
}
void cStreamdevServer::Init(void) {
void cStreamdevServer::Initialize(void)
{
if (m_Instance == NULL) {
if (StreamdevServerSetup.StartVTPServer) Register(new cComponentVTP);
if (StreamdevServerSetup.StartHTTPServer) Register(new cComponentHTTP);
m_Instance = new cStreamdevServer;
if (StreamdevServerSetup.StartVTPServer)
m_Instance->Register(new cComponentVTP);
if (StreamdevServerSetup.StartHTTPServer)
m_Instance->Register(new cComponentHTTP);
m_Instance->Start();
}
}
void cStreamdevServer::Exit(void) {
if (m_Instance != NULL) {
m_Instance->Stop();
DELETENULL(m_Instance);
void cStreamdevServer::Destruct(void)
{
DELETENULL(m_Instance);
}
void cStreamdevServer::Stop(void)
{
if (m_Active) {
m_Active = false;
Cancel(3);
}
}
void cStreamdevServer::Stop(void) {
m_Active = false;
Cancel(3);
}
void cStreamdevServer::Register(cServerComponent *Server) {
void cStreamdevServer::Register(cServerComponent *Server)
{
m_Servers.Add(Server);
}
void cStreamdevServer::Action(void) {
cTBSelect select;
#if VDRVERSNUM < 10300
isyslog("Streamdev: Server thread started (pid=%d)", getpid());
#endif
void cStreamdevServer::Action(void)
{
m_Active = true;
/* Initialize Server components, deleting those that failed */
for (cServerComponent *c = m_Servers.First(); c;) {
cServerComponent *next = m_Servers.Next(c);
if (!c->Init())
if (!c->Initialize())
m_Servers.Del(c);
c = next;
}
if (!m_Servers.Count()) {
esyslog("Streamdev: No server components registered, exiting");
if (m_Servers.Count() == 0) {
esyslog("ERROR: no streamdev server activated, exiting");
m_Active = false;
}
cTBSelect select;
while (m_Active) {
select.Clear();
/* Ask all Server components to register to the selector */
for (cServerComponent *c = m_Servers.First(); c; c = m_Servers.Next(c))
c->AddSelect(select);
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))
s->AddSelect(select);
{
select.Add(s->Socket(), false);
if (s->HasData())
select.Add(s->Socket(), true);
}
if (select.Select(1000) < 0) {
if (!m_Active) // Exit was requested while polling
continue;
esyslog("Streamdev: Fatal error, server exiting: %s", strerror(errno));
m_Active = false;
if (select.Select() < 0) {
if (m_Active) // no exit was requested while polling
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)) {
cServerConnection *client;
if ((client = c->CanAct(select)) != NULL) {
for (cServerComponent *c = m_Servers.First(); c; c = m_Servers.Next(c)){
if (select.CanRead(c->Socket())) {
cServerConnection *client = c->Accept();
m_Clients.Add(client);
if (m_Clients.Count() > StreamdevServerSetup.MaxClients) {
esyslog("Streamdev: Too many clients, rejecting %s:%d",
esyslog("streamdev: too many clients, rejecting %s:%d",
client->RemoteIp().c_str(), client->RemotePort());
client->Reject();
} else if (!StreamdevHosts.Acceptable(client->RemoteIpAddr())) {
esyslog("Streamdev: Client from %s:%d not allowed to connect",
esyslog("streamdev: client %s:%d not allowed to connect",
client->RemoteIp().c_str(), client->RemotePort());
client->Reject();
} else
@ -119,10 +118,18 @@ void cStreamdevServer::Action(void) {
/* Ask all Client connections to act on signalled sockets */
for (cServerConnection *s = m_Clients.First(); s;) {
bool result = true;
if (select.CanWrite(s->Socket()))
result = s->Write();
if (result && select.CanRead(s->Socket()))
result = s->Read();
cServerConnection *next = m_Clients.Next(s);
if (!s->CanAct(select)) {
isyslog("Streamdev: Closing connection to %s:%d",
s->RemoteIp().c_str(), s->RemotePort());
if (!result) {
isyslog("streamdev: closing streamdev connection to %s:%d",
s->RemoteIp().c_str(), s->RemotePort());
s->Close();
m_Clients.Del(s);
}
@ -130,19 +137,17 @@ void cStreamdevServer::Action(void) {
}
}
while (m_Clients.Count()) {
cServerConnection *client = m_Clients.First();
client->Close();
m_Clients.Del(client);
while (m_Clients.Count() > 0) {
cServerConnection *s = m_Clients.First();
s->Close();
m_Clients.Del(s);
}
while (m_Servers.Count()) {
cServerComponent *server = m_Servers.First();
server->Exit();
m_Servers.Del(server);
while (m_Servers.Count() > 0) {
cServerComponent *c = m_Servers.First();
c->Destruct();
m_Servers.Del(c);
}
#if VDRVERSNUM < 10300
isyslog("Streamdev: Server thread stopped");
#endif
m_Active = false;
}

View File

@ -1,5 +1,5 @@
/*
* $Id: server.h,v 1.1 2004/12/30 22:44:21 lordjaxom Exp $
* $Id: server.h,v 1.2 2005/05/09 20:22:29 lordjaxom Exp $
*/
#ifndef VDR_STREAMDEV_SERVER_H
@ -10,33 +10,36 @@
#include "server/component.h"
#include "server/connection.h"
#define STREAMDEVHOSTSPATH (*AddDirectory(cPlugin::ConfigDirectory(), "streamdevhosts.conf"))
class cStreamdevServer: public cThread {
private:
bool m_Active;
cServerComponents m_Servers;
cServerConnections m_Clients;
static cStreamdevServer *m_Instance;
static cStreamdevServer *m_Instance;
static cList<cServerComponent> m_Servers;
static cList<cServerConnection> m_Clients;
protected:
void Stop(void);
virtual void Action(void);
void Stop(void);
static void Register(cServerComponent *Server);
public:
cStreamdevServer(void);
virtual ~cStreamdevServer();
void Register(cServerComponent *Server);
static void Init(void);
static void Exit(void);
static void Initialize(void);
static void Destruct(void);
static bool Active(void);
};
inline bool cStreamdevServer::Active(void) {
return m_Instance && m_Instance->m_Clients.Count() > 0;
inline bool cStreamdevServer::Active(void)
{
return m_Instance != NULL
&& m_Instance->m_Clients.Count() > 0;
}
extern cSVDRPhosts StreamdevHosts;

View File

@ -1,5 +1,5 @@
/*
* $Id: setup.c,v 1.1 2004/12/30 22:44:21 lordjaxom Exp $
* $Id: setup.c,v 1.2 2005/05/09 20:22:29 lordjaxom Exp $
*/
#include <vdr/menuitems.h>
@ -72,7 +72,7 @@ void cStreamdevServerMenuSetupPage::Store(void) {
|| m_NewSetup.HTTPServerPort != StreamdevServerSetup.HTTPServerPort
|| strcmp(m_NewSetup.HTTPBindIP, StreamdevServerSetup.HTTPBindIP) != 0) {
restart = true;
cStreamdevServer::Exit();
cStreamdevServer::Destruct();
}
SetupStore("MaxClients", m_NewSetup.MaxClients);
@ -89,6 +89,6 @@ void cStreamdevServerMenuSetupPage::Store(void) {
StreamdevServerSetup = m_NewSetup;
if (restart)
cStreamdevServer::Init();
cStreamdevServer::Initialize();
}

View File

@ -1,5 +1,5 @@
/*
* $Id: streamer.c,v 1.13 2005/04/30 19:41:08 lordjaxom Exp $
* $Id: streamer.c,v 1.14 2005/05/09 20:22:29 lordjaxom Exp $
*/
#include <vdr/ringbuffer.h>
@ -16,7 +16,8 @@
// --- cStreamdevWriter -------------------------------------------------------
cStreamdevWriter::cStreamdevWriter(cTBSocket *Socket, cStreamdevStreamer *Streamer):
cStreamdevWriter::cStreamdevWriter(cTBSocket *Socket,
cStreamdevStreamer *Streamer):
cThread("streamdev-writer"),
m_Streamer(Streamer),
m_Socket(Socket),
@ -45,7 +46,7 @@ void cStreamdevWriter::Action(void)
offset = 0;
}
if (block) {
if (block != NULL) {
sel.Clear();
sel.Add(*m_Socket, true);
if (sel.Select(500) == -1) {
@ -130,8 +131,6 @@ void cStreamdevStreamer::Stop(void)
void cStreamdevStreamer::Action(void)
{
int max = 0;
m_Active = true;
while (m_Active) {
int got;

View File

@ -3,7 +3,7 @@
*
* See the README file for copyright information and how to reach the author.
*
* $Id: streamdev-server.c,v 1.1 2004/12/30 22:43:59 lordjaxom Exp $
* $Id: streamdev-server.c,v 1.2 2005/05/09 20:22:29 lordjaxom Exp $
*/
#include "streamdev-server.h"
@ -14,59 +14,73 @@
const char *cPluginStreamdevServer::DESCRIPTION = "VDR Streaming Server";
cPluginStreamdevServer::cPluginStreamdevServer(void) {
cPluginStreamdevServer::cPluginStreamdevServer(void)
{
}
cPluginStreamdevServer::~cPluginStreamdevServer() {
cStreamdevServer::Exit();
cPluginStreamdevServer::~cPluginStreamdevServer()
{
}
const char *cPluginStreamdevServer::Description(void) {
const char *cPluginStreamdevServer::Description(void)
{
return tr(DESCRIPTION);
}
bool cPluginStreamdevServer::Start(void) {
bool cPluginStreamdevServer::Start(void)
{
i18n_name = Name();
RegisterI18n(Phrases);
if (!StreamdevHosts.Load(STREAMDEVHOSTS, true, true)) {
esyslog("streamdev-server: error while loading %s", STREAMDEVHOSTS);
if (!StreamdevHosts.Load(STREAMDEVHOSTSPATH, true, true)) {
esyslog("streamdev-server: error while loading %s", STREAMDEVHOSTSPATH);
fprintf(stderr, "streamdev-server: error while loading %s\n");
if (access(STREAMDEVHOSTS, F_OK) != 0)
if (access(STREAMDEVHOSTSPATH, F_OK) != 0) {
fprintf(stderr, " Please install streamdevhosts.conf into the path "
"printed above. Without it\n"
" no client will be able to access your streaming-"
"server. An example can be\n"
" found together with this plugin's sources.\n");
" no client will be able to access your streaming-"
"server. An example can be\n"
" found together with this plugin's sources.\n");
}
return false;
}
cStreamdevServer::Init();
cStreamdevServer::Initialize();
return true;
return true;
}
bool cPluginStreamdevServer::Active(void) {
void cPluginStreamdevServer::Stop(void)
{
cStreamdevServer::Destruct();
}
bool cPluginStreamdevServer::Active(void)
{
return cStreamdevServer::Active();
}
const char *cPluginStreamdevServer::MainMenuEntry(void) {
const char *cPluginStreamdevServer::MainMenuEntry(void)
{
if (StreamdevServerSetup.SuspendMode == smOffer && !cSuspendCtl::IsActive())
return tr("Suspend Live TV");
return NULL;
}
cOsdObject *cPluginStreamdevServer::MainMenuAction(void) {
cOsdObject *cPluginStreamdevServer::MainMenuAction(void)
{
cControl::Launch(new cSuspendCtl);
return NULL;
}
cMenuSetupPage *cPluginStreamdevServer::SetupMenu(void) {
return new cStreamdevServerMenuSetupPage;
cMenuSetupPage *cPluginStreamdevServer::SetupMenu(void)
{
return new cStreamdevServerMenuSetupPage;
}
bool cPluginStreamdevServer::SetupParse(const char *Name, const char *Value) {
return StreamdevServerSetup.SetupParse(Name, Value);
bool cPluginStreamdevServer::SetupParse(const char *Name, const char *Value)
{
return StreamdevServerSetup.SetupParse(Name, Value);
}
VDRPLUGINCREATOR(cPluginStreamdevServer); // Don't touch this!

View File

@ -1,5 +1,5 @@
/*
* $Id: streamdev-server.h,v 1.1 2004/12/30 22:43:59 lordjaxom Exp $
* $Id: streamdev-server.h,v 1.2 2005/05/09 20:22:29 lordjaxom Exp $
*/
#ifndef VDR_STREAMDEVSERVER_H
@ -14,16 +14,18 @@ private:
static const char *DESCRIPTION;
public:
cPluginStreamdevServer(void);
virtual ~cPluginStreamdevServer();
virtual const char *Version(void) { return VERSION; }
virtual const char *Description(void);
virtual bool Start(void);
cPluginStreamdevServer(void);
virtual ~cPluginStreamdevServer();
virtual const char *Version(void) { return VERSION; }
virtual const char *Description(void);
virtual bool Start(void);
virtual void Stop(void);
virtual bool Active(void);
virtual const char *MainMenuEntry(void);
virtual cOsdObject *MainMenuAction(void);
virtual cMenuSetupPage *SetupMenu(void);
virtual bool SetupParse(const char *Name, const char *Value);
virtual const char *MainMenuEntry(void);
virtual cOsdObject *MainMenuAction(void);
virtual cMenuSetupPage *SetupMenu(void);
virtual bool SetupParse(const char *Name, const char *Value);
};
#endif // VDR_STREAMDEVSERVER_H