summaryrefslogtreecommitdiff
path: root/server
diff options
context:
space:
mode:
authorlordjaxom <lordjaxom>2005-05-09 20:22:29 +0000
committerlordjaxom <lordjaxom>2005-05-09 20:22:29 +0000
commit450c8fd4a7ec7eb878abfce0e4a499e03762b4f8 (patch)
treecedc263aad1297fdb64a813ff83e424ee4023925 /server
parent3eec47314d70d513b494750312a877f29d070eb8 (diff)
downloadvdr-plugin-streamdev-450c8fd4a7ec7eb878abfce0e4a499e03762b4f8.tar.gz
vdr-plugin-streamdev-450c8fd4a7ec7eb878abfce0e4a499e03762b4f8.tar.bz2
- added TS compatibility mode
Diffstat (limited to 'server')
-rw-r--r--server/component.c50
-rw-r--r--server/component.h27
-rw-r--r--server/componentHTTP.c11
-rw-r--r--server/componentHTTP.h16
-rw-r--r--server/componentVTP.c11
-rw-r--r--server/componentVTP.h17
-rw-r--r--server/connection.c151
-rw-r--r--server/connection.h73
-rw-r--r--server/connectionHTTP.c45
-rw-r--r--server/connectionVTP.c945
-rw-r--r--server/connectionVTP.h42
-rw-r--r--server/server.c131
-rw-r--r--server/server.h27
-rw-r--r--server/setup.c6
-rw-r--r--server/streamer.c9
15 files changed, 1001 insertions, 560 deletions
diff --git a/server/component.c b/server/component.c
index 61e7c6b..1a584b5 100644
--- a/server/component.c
+++ b/server/component.c
@@ -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;
}
diff --git a/server/component.h b/server/component.h
index 2f8e605..8703348 100644
--- a/server/component.h
+++ b/server/component.h
@@ -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);
- /* Adds the listening socket to the Select object */
- virtual void AddSelect(cTBSelect &Select) const { Select.Add(m_Listen); }
-
- /* Accepts the connection on a NewConnection() object and calls the
- Welcome() on it, override if you want to do things different */
- virtual cServerConnection *CanAct(const cTBSelect &Select);
+ /* Get the listening socket's file number */
+ virtual int Socket(void) const { return (int)m_Listen; }
- /* Returns a new connection object for CanAct */
- virtual cServerConnection *NewConnection(void) const = 0;
-};
+ /* Adds the listening socket to the Select object */
+ virtual void Add(cTBSelect &Select) const { Select.Add(m_Listen); }
-class cServerComponents: public cList<cServerComponent> {
+ /* Accepts the connection on a NewClient() object and calls the
+ Welcome() on it, override if you want to do things different */
+ virtual cServerConnection *Accept(void);
};
#endif // VDR_STREAMDEV_SERVERS_COMPONENT_H
diff --git a/server/componentHTTP.c b/server/componentHTTP.c
index 035cb01..70e95e9 100644
--- a/server/componentHTTP.c
+++ b/server/componentHTTP.c
@@ -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"
@@ -7,9 +7,12 @@
#include "server/setup.h"
cComponentHTTP::cComponentHTTP(void):
- cServerComponent("HTTP", StreamdevServerSetup.HTTPBindIP,
- StreamdevServerSetup.HTTPServerPort) {
+ cServerComponent("HTTP", StreamdevServerSetup.HTTPBindIP,
+ StreamdevServerSetup.HTTPServerPort)
+{
}
-cComponentHTTP::~cComponentHTTP() {
+cServerConnection *cComponentHTTP::NewClient(void)
+{
+ return new cConnectionHTTP;
}
diff --git a/server/componentHTTP.h b/server/componentHTTP.h
index 46174d9..29dc087 100644
--- a/server/componentHTTP.h
+++ b/server/componentHTTP.h
@@ -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
diff --git a/server/componentVTP.c b/server/componentVTP.c
index 5fb9dcd..ed2df1c 100644
--- a/server/componentVTP.c
+++ b/server/componentVTP.c
@@ -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"
@@ -7,9 +7,12 @@
#include "server/setup.h"
cComponentVTP::cComponentVTP(void):
- cServerComponent("VTP", StreamdevServerSetup.VTPBindIP,
- StreamdevServerSetup.VTPServerPort) {
+ cServerComponent("VTP", StreamdevServerSetup.VTPBindIP,
+ StreamdevServerSetup.VTPServerPort)
+{
}
-cComponentVTP::~cComponentVTP() {
+cServerConnection *cComponentVTP::NewClient(void)
+{
+ return new cConnectionVTP;
}
diff --git a/server/componentVTP.h b/server/componentVTP.h
index fe411ff..4f61eb5 100644
--- a/server/componentVTP.h
+++ b/server/componentVTP.h
@@ -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
diff --git a/server/connection.c b/server/connection.c
index 762d184..38ba214 100644
--- a/server/connection.c
+++ b/server/connection.c
@@ -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,96 +11,113 @@
#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;
- }
+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;
+ }
- m_RdBytes += b;
- m_RdBuf[m_RdBytes] = '\0';
- return ParseBuffer();
+ if (b == 0) {
+ isyslog("client (%s) %s:%d has closed connection",
+ 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));
+ 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_WrOffs += b;
- if (m_WrOffs == m_WrBytes) {
- m_WrBytes = 0;
- m_WrOffs = 0;
- }
+ m_ReadBytes -= ++end - m_ReadBuffer;
+ if (m_ReadBytes > 0)
+ memmove(m_ReadBuffer, end, m_ReadBytes);
}
- if (m_WrBytes == 0) {
- if (m_DeferClose)
- return false;
- Flushed();
+ 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 true;
+
+ return result;
}
-bool cServerConnection::ParseBuffer(void) {
- char *ep;
- bool res;
-
- 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)
+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();
}
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());
+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);
+
+ 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());
-
- m_WrBytes += Message.size();
- m_WrBuf[m_WrBytes++] = '\015';
- m_WrBuf[m_WrBytes++] = '\012';
+ Dprintf("OUT: |%s|\n", buffer);
+ memcpy(m_WriteBuffer + m_WriteBytes, buffer, length);
+ free(buffer);
+
+ 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");
diff --git a/server/connection.h b/server/connection.h
index a4a4379..f68f84a 100644
--- a/server/connection.h
+++ b/server/connection.h
@@ -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;
+ const char *m_Protocol;
+ bool m_DeferClose;
+ bool m_Pending;
+
+ char m_ReadBuffer[MAXPARSEBUFFER];
+ uint m_ReadBytes;
- char m_WrBuf[8192];
- uint m_WrBytes;
- uint m_WrOffs;
+ char m_WriteBuffer[MAXPARSEBUFFER];
+ uint m_WriteBytes;
+ uint m_WriteIndex;
- const char *m_Protocol;
+protected:
+ /* Will be called when a command terminated by a newline has been
+ received */
+ virtual bool Command(char *Cmd) = 0;
- bool m_DeferClose;
+ /* 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
diff --git a/server/connectionHTTP.c b/server/connectionHTTP.c
index 2c912bc..ffd987a 100644
--- a/server/connectionHTTP.c
+++ b/server/connectionHTTP.c
@@ -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
diff --git a/server/connectionVTP.c b/server/connectionVTP.c
index a4ea245..b66d224 100644
--- a/server/connectionVTP.c
+++ b/server/connectionVTP.c
@@ -1,5 +1,5 @@
/*
- * $Id: connectionVTP.c,v 1.6 2005/04/24 16:26:14 lordjaxom Exp $
+ * $Id: connectionVTP.c,v 1.7 2005/05/09 20:22:29 lordjaxom Exp $
*/
#include "server/connectionVTP.h"
@@ -17,82 +17,562 @@
/* VTP Response codes:
220: Service ready
221: Service closing connection
+ 451: Requested action aborted: try again
500: Syntax error or Command unrecognized
501: Wrong parameters or missing parameters
- 550: Action not done
+ 550: Requested action not taken
551: Data connection not accepted
560: Channel not available currently
- 561: Capability not known
+ 561: Capability not known
562: Pid not available currently
563: Recording not available (currently?)
*/
-cConnectionVTP::cConnectionVTP(void): cServerConnection("VTP") {
- m_LiveStreamer = NULL;
- memset(m_DataSockets, 0, sizeof(cTBSocket*) * si_Count);
+// --- cLSTEHandler -----------------------------------------------------------
+
+class cLSTEHandler
+{
+private:
+ enum eStates { Channel, Event, Title, Subtitle, Description, Vps,
+ EndEvent, EndChannel, EndEPG };
+ cConnectionVTP *m_Client;
+ cSchedulesLock *m_SchedulesLock;
+ const cSchedules *m_Schedules;
+ const cSchedule *m_Schedule;
+ const cEvent *m_Event;
+ int m_Errno;
+ char *m_Error;
+ eStates m_State;
+ bool m_Traverse;
+public:
+ cLSTEHandler(cConnectionVTP *Client, const char *Option);
+ ~cLSTEHandler();
+ bool Next(bool &Last);
+};
+
+cLSTEHandler::cLSTEHandler(cConnectionVTP *Client, const char *Option):
+ m_Client(Client),
+ m_SchedulesLock(new cSchedulesLock(false, 500)),
+ m_Schedules(cSchedules::Schedules(*m_SchedulesLock)),
+ m_Schedule(NULL),
+ m_Event(NULL),
+ m_Errno(0),
+ m_Error(NULL),
+ m_State(Channel),
+ m_Traverse(false)
+{
+ eDumpMode dumpmode = dmAll;
+ time_t attime = 0;
+
+ if (m_Schedules != NULL && *Option) {
+ char buf[strlen(Option) + 1];
+ strcpy(buf, Option);
+ const char *delim = " \t";
+ char *strtok_next;
+ char *p = strtok_r(buf, delim, &strtok_next);
+ while (p && dumpmode == dmAll) {
+ if (strcasecmp(p, "NOW") == 0)
+ dumpmode = dmPresent;
+ else if (strcasecmp(p, "NEXT") == 0)
+ dumpmode = dmFollowing;
+ else if (strcasecmp(p, "AT") == 0) {
+ dumpmode = dmAtTime;
+ if ((p = strtok_r(NULL, delim, &strtok_next)) != NULL) {
+ if (isnumber(p))
+ attime = strtol(p, NULL, 10);
+ else {
+ m_Errno = 501;
+ m_Error = strdup("Invalid time");
+ break;
+ }
+ } else {
+ m_Errno = 501;
+ m_Error = strdup("Missing time");
+ break;
+ }
+ } else if (!m_Schedule) {
+ cChannel* Channel = NULL;
+ if (isnumber(p))
+ Channel = Channels.GetByNumber(strtol(Option, NULL, 10));
+ else
+ Channel = Channels.GetByChannelID(tChannelID::FromString(
+ Option));
+ if (Channel) {
+ m_Schedule = m_Schedules->GetSchedule(Channel->GetChannelID());
+ if (!m_Schedule) {
+ m_Errno = 550;
+ m_Error = strdup("No schedule found");
+ break;
+ }
+ } else {
+ m_Errno = 550;
+ asprintf(&m_Error, "Channel \"%s\" not defined", p);
+ break;
+ }
+ } else {
+ m_Errno = 501;
+ asprintf(&m_Error, "Unknown option: \"%s\"", p);
+ break;
+ }
+ p = strtok_r(NULL, delim, &strtok_next);
+ }
+ } else if (m_Schedules == NULL) {
+ m_Errno = 451;
+ m_Error = strdup("EPG data is being modified, try again");
+ }
+
+ if (m_Error == NULL) {
+ if (m_Schedule != NULL)
+ m_Schedules = NULL;
+ else if (m_Schedules != NULL)
+ m_Schedule = m_Schedules->First();
+
+ if (m_Schedule != NULL && m_Schedule->Events() != NULL) {
+ switch (dumpmode) {
+ case dmAll: m_Event = m_Schedule->Events()->First();
+ m_Traverse = true;
+ break;
+ case dmPresent: m_Event = m_Schedule->GetPresentEvent();
+ break;
+ case dmFollowing: m_Event = m_Schedule->GetFollowingEvent();
+ break;
+ case dmAtTime: m_Event = m_Schedule->GetEventAround(attime);
+ break;
+
+ }
+ }
+ }
+}
+
+cLSTEHandler::~cLSTEHandler()
+{
+ delete m_SchedulesLock;
+ if (m_Error != NULL)
+ free(m_Error);
+}
+
+bool cLSTEHandler::Next(bool &Last)
+{
+ char *buffer;
+
+ if (m_Error != NULL) {
+ Last = true;
+ cString str(m_Error, true);
+ m_Error = NULL;
+ return m_Client->Respond(m_Errno, *str);
+ }
+
+ Last = false;
+ switch (m_State) {
+ case Channel:
+ if (m_Schedule != NULL) {
+ cChannel *channel = Channels.GetByChannelID(m_Schedule->ChannelID(),
+ true);
+ m_State = Event;
+ return m_Client->Respond(-215, "C %s %s",
+ *channel->GetChannelID().ToString(),
+ channel->Name());
+ } else {
+ m_State = EndEPG;
+ return Next(Last);
+ }
+ break;
+
+ case Event:
+ if (m_Event != NULL) {
+ m_State = Title;
+ return m_Client->Respond(-215, "E %u %ld %d %X", m_Event->EventID(),
+ m_Event->StartTime(), m_Event->Duration(),
+ m_Event->TableID());
+ } else {
+ m_State = EndChannel;
+ return Next(Last);
+ }
+ break;
+
+ case Title:
+ m_State = Subtitle;
+ if (!isempty(m_Event->Title()))
+ return m_Client->Respond(-215, "T %s", m_Event->Title());
+ else
+ return Next(Last);
+ break;
+
+ case Subtitle:
+ m_State = Description;
+ if (!isempty(m_Event->ShortText()))
+ return m_Client->Respond(-215, "S %s", m_Event->ShortText());
+ else
+ return Next(Last);
+ break;
+
+ case Description:
+ m_State = Vps;
+ if (!isempty(m_Event->Description())) {
+ char *copy = strdup(m_Event->Description());
+ cString cpy(copy, true);
+ strreplace(copy, '\n', '|');
+ return m_Client->Respond(-215, "D %s", copy);
+ } else
+ return Next(Last);
+ break;
+
+ case Vps:
+ m_State = EndEvent;
+ if (m_Event->Vps())
+ return m_Client->Respond(-215, "V %ld", m_Event->Vps());
+ else
+ return Next(Last);
+ break;
+
+ case EndEvent:
+ if (m_Traverse)
+ m_Event = m_Schedule->Events()->Next(m_Event);
+ else
+ m_Event = NULL;
+
+ if (m_Event != NULL)
+ m_State = Event;
+ else
+ m_State = EndChannel;
+
+ return m_Client->Respond(-215, "e");
+
+ case EndChannel:
+ if (m_Schedules != NULL) {
+ m_Schedule = m_Schedules->Next(m_Schedule);
+ if (m_Schedule != NULL) {
+ if (m_Schedule->Events() != NULL)
+ m_Event = m_Schedule->Events()->First();
+ m_State = Channel;
+ }
+ }
+
+ if (m_Schedules == NULL || m_Schedule == NULL)
+ m_State = EndEPG;
+
+ return m_Client->Respond(-215, "c");
+
+ case EndEPG:
+ Last = true;
+ return m_Client->Respond(215, "End of EPG data");
+ }
+ return false;
+}
+
+// --- cLSTCHandler -----------------------------------------------------------
+
+class cLSTCHandler
+{
+private:
+ cConnectionVTP *m_Client;
+ const cChannel *m_Channel;
+ char *m_Option;
+ int m_Errno;
+ char *m_Error;
+ bool m_Traverse;
+public:
+ cLSTCHandler(cConnectionVTP *Client, const char *Option);
+ ~cLSTCHandler();
+ bool Next(bool &Last);
+};
+
+cLSTCHandler::cLSTCHandler(cConnectionVTP *Client, const char *Option):
+ m_Client(Client),
+ m_Channel(NULL),
+ m_Option(NULL),
+ m_Errno(0),
+ m_Error(NULL),
+ m_Traverse(false)
+{
+ if (!Channels.Lock(false, 500)) {
+ m_Errno = 451;
+ m_Error = strdup("Channels are being modified - try again");
+ } else if (*Option) {
+ if (isnumber(Option)) {
+ m_Channel = Channels.GetByNumber(strtol(Option, NULL, 10));
+ if (m_Channel == NULL) {
+ m_Errno = 501;
+ asprintf(&m_Error, "Channel \"%s\" not defined", Option);
+ return;
+ }
+ } else {
+ int i = 1;
+ m_Traverse = true;
+ m_Option = strdup(Option);
+ while (i <= Channels.MaxNumber()) {
+ m_Channel = Channels.GetByNumber(i, 1);
+ if (strcasestr(m_Channel->Name(), Option) != NULL)
+ break;
+ i = m_Channel->Number() + 1;
+ }
+
+ if (i > Channels.MaxNumber()) {
+ m_Errno = 501;
+ asprintf(&m_Error, "Channel \"%s\" not defined", Option);
+ return;
+ }
+ }
+ } else if (Channels.MaxNumber() >= 1) {
+ m_Channel = Channels.GetByNumber(1, 1);
+ m_Traverse = true;
+ } else {
+ m_Errno = 550;
+ m_Error = strdup("No channels defined");
+ }
+}
+
+cLSTCHandler::~cLSTCHandler()
+{
+ Channels.Unlock();
+ if (m_Error != NULL)
+ free(m_Error);
+ if (m_Option != NULL)
+ free(m_Option);
+}
+
+bool cLSTCHandler::Next(bool &Last)
+{
+ if (m_Error != NULL) {
+ Last = true;
+ cString str(m_Error, true);
+ m_Error = NULL;
+ return m_Client->Respond(m_Errno, *str);
+ }
+
+ int number;
+ char *buffer;
+
+ number = m_Channel->Number();
+ buffer = strdup(*m_Channel->ToText());
+ buffer[strlen(buffer) - 1] = '\0'; // remove \n
+ cString str(buffer, true);
+
+ Last = true;
+ if (m_Traverse) {
+ int i = m_Channel->Number() + 1;
+ while (i <= Channels.MaxNumber()) {
+ m_Channel = Channels.GetByNumber(i, 1);
+ if (m_Channel != NULL) {
+ if (m_Option == NULL || strcasestr(m_Channel->Name(),
+ m_Option) != NULL)
+ break;
+ i = m_Channel->Number() + 1;
+ } else {
+ m_Errno = 501;
+ asprintf(&m_Error, "Channel \"%d\" not found", i);
+ }
+ }
+
+ if (i < Channels.MaxNumber())
+ Last = false;
+ }
+
+ return m_Client->Respond(Last ? 250 : -250, "%d %s", number, buffer);
+}
+
+// --- cLSTTHandler -----------------------------------------------------------
+
+class cLSTTHandler
+{
+private:
+ cConnectionVTP *m_Client;
+ cTimer *m_Timer;
+ int m_Index;
+ int m_Errno;
+ char *m_Error;
+ bool m_Traverse;
+public:
+ cLSTTHandler(cConnectionVTP *Client, const char *Option);
+ ~cLSTTHandler();
+ bool Next(bool &Last);
+};
+
+cLSTTHandler::cLSTTHandler(cConnectionVTP *Client, const char *Option):
+ m_Client(Client),
+ m_Timer(NULL),
+ m_Index(0),
+ m_Errno(0),
+ m_Error(NULL),
+ m_Traverse(false)
+{
+ if (*Option) {
+ if (isnumber(Option)) {
+ m_Timer = Timers.Get(strtol(Option, NULL, 10) - 1);
+ if (m_Timer == NULL) {
+ m_Errno = 501;
+ asprintf(&m_Error, "Timer \"%s\" not defined", Option);
+ }
+ } else {
+ m_Errno = 501;
+ asprintf(&m_Error, "Error in timer number \"%s\"", Option);
+ }
+ } else if (Timers.Count()) {
+ m_Traverse = true;
+ m_Index = 0;
+ m_Timer = Timers.Get(m_Index);
+ if (m_Timer == NULL) {
+ m_Errno = 501;
+ asprintf(&m_Error, "Timer \"%d\" not found", m_Index + 1);
+ }
+ } else {
+ m_Errno = 550;
+ m_Error = strdup("No timers defined");
+ }
+}
+
+cLSTTHandler::~cLSTTHandler()
+{
+ if (m_Error != NULL)
+ free(m_Error);
}
-cConnectionVTP::~cConnectionVTP() {
- if (m_LiveStreamer != NULL) delete m_LiveStreamer;
+bool cLSTTHandler::Next(bool &Last)
+{
+ if (m_Error != NULL) {
+ Last = true;
+ cString str(m_Error, true);
+ m_Error = NULL;
+ return m_Client->Respond(m_Errno, *str);
+ }
+
+ bool result;
+ char *buffer;
+ Last = !m_Traverse || m_Index >= Timers.Count() - 1;
+ buffer = strdup(*m_Timer->ToText());
+ buffer[strlen(buffer) - 1] = '\0'; // strip \n
+ result = m_Client->Respond(Last ? 250 : -250, "%d %s", m_Timer->Index() + 1,
+ buffer);
+ free(buffer);
+
+ if (m_Traverse && !Last) {
+ m_Timer = Timers.Get(++m_Index);
+ if (m_Timer == NULL) {
+ m_Errno = 501;
+ asprintf(&m_Error, "Timer \"%d\" not found", m_Index + 1);
+ }
+ }
+ return result;
+}
- for (int idx = 0; idx < si_Count; ++idx)
- if (m_DataSockets[idx] != NULL) delete m_DataSockets[idx];
+// --- cConnectionVTP ---------------------------------------------------------
+
+cConnectionVTP::cConnectionVTP(void):
+ cServerConnection("VTP"),
+ m_LiveSocket(NULL),
+ m_LiveStreamer(NULL),
+ m_LastCommand(NULL),
+ m_NoTSPIDS(false),
+ m_LSTEHandler(NULL),
+ m_LSTCHandler(NULL),
+ m_LSTTHandler(NULL)
+{
}
-void cConnectionVTP::Welcome(void) {
+cConnectionVTP::~cConnectionVTP()
+{
+ if (m_LastCommand != NULL)
+ free(m_LastCommand);
+ delete m_LiveStreamer;
+ delete m_LiveSocket;
+ delete m_LSTTHandler;
+ delete m_LSTCHandler;
+ delete m_LSTEHandler;
+}
+
+void cConnectionVTP::Welcome(void)
+{
Respond(220, "Welcome to Video Disk Recorder (VTP)");
}
-void cConnectionVTP::Reject(void) {
+void cConnectionVTP::Reject(void)
+{
Respond(221, "Too many clients or client not allowed to connect");
cServerConnection::Reject();
}
-void cConnectionVTP::Detach(void) {
+void cConnectionVTP::Detach(void)
+{
if (m_LiveStreamer != NULL) m_LiveStreamer->Detach();
}
-void cConnectionVTP::Attach(void) {
+void cConnectionVTP::Attach(void)
+{
if (m_LiveStreamer != NULL) m_LiveStreamer->Attach();
}
-bool cConnectionVTP::Command(char *Cmd) {
- char *ep;
- if ((ep = strchr(Cmd, ' ')) != NULL)
- *(ep++) = '\0';
- else
- ep = Cmd + strlen(Cmd);
-
- if (strcasecmp(Cmd, "CAPS") == 0) return CmdCAPS(ep);
- else if (strcasecmp(Cmd, "PROV") == 0) return CmdPROV(ep);
- else if (strcasecmp(Cmd, "PORT") == 0) return CmdPORT(ep);
- else if (strcasecmp(Cmd, "TUNE") == 0) return CmdTUNE(ep);
- else if (strcasecmp(Cmd, "ADDP") == 0) return CmdADDP(ep);
- else if (strcasecmp(Cmd, "DELP") == 0) return CmdDELP(ep);
- else if (strcasecmp(Cmd, "ADDF") == 0) return CmdADDF(ep);
- else if (strcasecmp(Cmd, "DELF") == 0) return CmdDELF(ep);
- else if (strcasecmp(Cmd, "ABRT") == 0) return CmdABRT(ep);
- else if (strcasecmp(Cmd, "QUIT") == 0) return CmdQUIT(ep);
- else if (strcasecmp(Cmd, "SUSP") == 0) return CmdSUSP(ep);
+bool cConnectionVTP::Command(char *Cmd)
+{
+ char *param = NULL;
+
+ if (Cmd != NULL) {
+ if (m_LastCommand != NULL) {
+ esyslog("ERROR: streamdev: protocol violation (VTP) from %s:%d",
+ RemoteIp().c_str(), RemotePort());
+ return false;
+ }
+
+ if ((param = strchr(Cmd, ' ')) != NULL)
+ *(param++) = '\0';
+ else
+ param = Cmd + strlen(Cmd);
+ m_LastCommand = strdup(Cmd);
+ } else {
+ Cmd = m_LastCommand;
+ param = NULL;
+ }
+
+ if (strcasecmp(Cmd, "LSTE") == 0) return CmdLSTE(param);
+ //else if (strcasecmp(Cmd, "LSTR") == 0) return CmdLSTR(param);
+ else if (strcasecmp(Cmd, "LSTT") == 0) return CmdLSTT(param);
+ else if (strcasecmp(Cmd, "LSTC") == 0) return CmdLSTC(param);
+
+ if (param == NULL) {
+ esyslog("ERROR: streamdev: this seriously shouldn't happen at %s:%d",
+ __FILE__, __LINE__);
+ return false;
+ }
+
+ if (strcasecmp(Cmd, "CAPS") == 0) return CmdCAPS(param);
+ else if (strcasecmp(Cmd, "PROV") == 0) return CmdPROV(param);
+ else if (strcasecmp(Cmd, "PORT") == 0) return CmdPORT(param);
+ else if (strcasecmp(Cmd, "TUNE") == 0) return CmdTUNE(param);
+ else if (strcasecmp(Cmd, "ADDP") == 0) return CmdADDP(param);
+ else if (strcasecmp(Cmd, "DELP") == 0) return CmdDELP(param);
+ else if (strcasecmp(Cmd, "ADDF") == 0) return CmdADDF(param);
+ else if (strcasecmp(Cmd, "DELF") == 0) return CmdDELF(param);
+ else if (strcasecmp(Cmd, "ABRT") == 0) return CmdABRT(param);
+ else if (strcasecmp(Cmd, "QUIT") == 0) return CmdQUIT(param);
+ else if (strcasecmp(Cmd, "SUSP") == 0) return CmdSUSP(param);
// Commands adopted from SVDRP
- else if (strcasecmp(Cmd, "LSTE") == 0) return CmdLSTE(ep);
- else if (strcasecmp(Cmd, "LSTR") == 0) return CmdLSTR(ep);
- else if (strcasecmp(Cmd, "DELR") == 0) return CmdDELR(ep);
- else if (strcasecmp(Cmd, "LSTT") == 0) return CmdLSTT(ep);
- else if (strcasecmp(Cmd, "MODT") == 0) return CmdMODT(ep);
- else if (strcasecmp(Cmd, "NEWT") == 0) return CmdNEWT(ep);
- else if (strcasecmp(Cmd, "DELT") == 0) return CmdDELT(ep);
+ //else if (strcasecmp(Cmd, "DELR") == 0) return CmdDELR(param);
+ else if (strcasecmp(Cmd, "MODT") == 0) return CmdMODT(param);
+ else if (strcasecmp(Cmd, "NEWT") == 0) return CmdNEWT(param);
+ else if (strcasecmp(Cmd, "DELT") == 0) return CmdDELT(param);
else
- return Respond(500, (std::string)"Unknown Command '" + Cmd + "'");
+ return Respond(500, "Unknown Command \"%s\"", Cmd);
}
-bool cConnectionVTP::CmdCAPS(char *Opts) {
- if (strcasecmp(Opts, "TSPIDS") == 0)
- return Respond(220, (std::string)"Capability \"" + Opts + "\" accepted");
- return Respond(561, (std::string)"Capability \"" + Opts + "\" not known");
+bool cConnectionVTP::CmdCAPS(char *Opts)
+{
+ char *buffer;
+
+ if (strcasecmp(Opts, "TS") == 0) {
+ m_NoTSPIDS = true;
+ return Respond(220, "Ignored, capability \"%s\" accepted for "
+ "compatibility", Opts);
+ }
+
+ if (strcasecmp(Opts, "TSPIDS") == 0) {
+ m_NoTSPIDS = false;
+ return Respond(220, "Capability \"%s\" accepted", Opts);
+ }
+
+ return Respond(561, "Capability \"%s\" not known", Opts);
}
-bool cConnectionVTP::CmdPROV(char *Opts) {
+bool cConnectionVTP::CmdPROV(char *Opts)
+{
const cChannel *chan;
int prio;
char *ep;
@@ -103,14 +583,15 @@ bool cConnectionVTP::CmdPROV(char *Opts) {
Opts = skipspace(ep);
if ((chan = ChannelFromString(Opts)) == NULL)
- return Respond(550, (std::string)"Undefined channel \"" + Opts + "\"");
+ return Respond(550, "Undefined channel \"%s\"", Opts);
return GetDevice(chan, prio) != NULL
? Respond(220, "Channel available")
: Respond(560, "Channel not available");
}
-bool cConnectionVTP::CmdPORT(char *Opts) {
+bool cConnectionVTP::CmdPORT(char *Opts)
+{
uint id, dataport = 0;
char dataip[20];
char *ep, *ipoffs;
@@ -120,8 +601,8 @@ bool cConnectionVTP::CmdPORT(char *Opts) {
if (ep == Opts || !isspace(*ep))
return Respond(500, "Use: PORT Id Destination");
- if (id >= si_Count)
- return Respond(501, (std::string)"Wrong connection id " + (const char*)itoa(id));
+ if (id != 0)
+ return Respond(501, "Wrong connection id %d", id);
Opts = skipspace(ep);
n = 0;
@@ -148,26 +629,27 @@ bool cConnectionVTP::CmdPORT(char *Opts) {
isyslog("Streamdev: Setting data connection to %s:%d", dataip, dataport);
- m_DataSockets[id] = new cTBSocket(SOCK_STREAM);
- if (!m_DataSockets[id]->Connect(dataip, dataport)) {
+ m_LiveSocket = new cTBSocket(SOCK_STREAM);
+ if (!m_LiveSocket->Connect(dataip, dataport)) {
esyslog("ERROR: Streamdev: Couldn't open data connection to %s:%d: %s",
dataip, dataport, strerror(errno));
- DELETENULL(m_DataSockets[id]);
+ DELETENULL(m_LiveSocket);
return Respond(551, "Couldn't open data connection");
}
if (id == siLive)
- m_LiveStreamer->Start(m_DataSockets[id]);
+ m_LiveStreamer->Start(m_LiveSocket);
return Respond(220, "Port command ok, data connection opened");
}
-bool cConnectionVTP::CmdTUNE(char *Opts) {
+bool cConnectionVTP::CmdTUNE(char *Opts)
+{
const cChannel *chan;
cDevice *dev;
if ((chan = ChannelFromString(Opts)) == NULL)
- return Respond(550, (std::string)"Undefined channel \"" + Opts + "\"");
+ return Respond(550, "Undefined channel \"%s\"", Opts);
if ((dev = GetDevice(chan, 0)) == NULL)
return Respond(560, "Channel not available");
@@ -177,13 +659,14 @@ bool cConnectionVTP::CmdTUNE(char *Opts) {
delete m_LiveStreamer;
m_LiveStreamer = new cStreamdevLiveStreamer(1);
- m_LiveStreamer->SetChannel(chan, stTSPIDS);
+ m_LiveStreamer->SetChannel(chan, m_NoTSPIDS ? stTS : stTSPIDS);
m_LiveStreamer->SetDevice(dev);
return Respond(220, "Channel tuned");
}
-bool cConnectionVTP::CmdADDP(char *Opts) {
+bool cConnectionVTP::CmdADDP(char *Opts)
+{
int pid;
char *end;
@@ -192,11 +675,12 @@ bool cConnectionVTP::CmdADDP(char *Opts) {
return Respond(500, "Use: ADDP Pid");
return m_LiveStreamer && m_LiveStreamer->SetPid(pid, true)
- ? Respond(220, (std::string)"Pid " + (const char*)itoa(pid) + " available")
- : Respond(560, (std::string)"Pid " + (const char*)itoa(pid) + " not available");
+ ? Respond(220, "Pid %d available", pid)
+ : Respond(560, "Pid %d not available", pid);
}
-bool cConnectionVTP::CmdDELP(char *Opts) {
+bool cConnectionVTP::CmdDELP(char *Opts)
+{
int pid;
char *end;
@@ -205,11 +689,12 @@ bool cConnectionVTP::CmdDELP(char *Opts) {
return Respond(500, "Use: DELP Pid");
return m_LiveStreamer && m_LiveStreamer->SetPid(pid, false)
- ? Respond(220, (std::string)"Pid " + (const char*)itoa(pid) + " stopped")
- : Respond(560, (std::string)"Pid " + (const char*)itoa(pid) + " not transferring");
+ ? Respond(220, "Pid %d stopped", pid)
+ : Respond(560, "Pid %d not transferring", pid);
}
-bool cConnectionVTP::CmdADDF(char *Opts) {
+bool cConnectionVTP::CmdADDF(char *Opts)
+{
#if VDRVERSNUM >= 10300
int pid, tid, mask;
char *ep;
@@ -230,14 +715,15 @@ bool cConnectionVTP::CmdADDF(char *Opts) {
return Respond(500, "Use: ADDF Pid Tid Mask");
return m_LiveStreamer->SetFilter(pid, tid, mask, true)
- ? Respond(220, (std::string)"Filter " + (const char*)itoa(pid) + " transferring")
- : Respond(560, (std::string)"Filter " + (const char*)itoa(pid) + " not available");
+ ? Respond(220, "Filter %d transferring", pid)
+ : Respond(560, "Filter %d not available", pid);
#else
return Respond(500, "ADDF known but unimplemented with VDR < 1.3.0");
#endif
}
-bool cConnectionVTP::CmdDELF(char *Opts) {
+bool cConnectionVTP::CmdDELF(char *Opts)
+{
#if VDRVERSNUM >= 10307
int pid, tid, mask;
char *ep;
@@ -258,14 +744,15 @@ bool cConnectionVTP::CmdDELF(char *Opts) {
return Respond(500, "Use: DELF Pid Tid Mask");
return m_LiveStreamer->SetFilter(pid, tid, mask, false)
- ? Respond(220, (std::string)"Filter " + (const char*)itoa(pid) + " stopped")
- : Respond(560, (std::string)"Filter " + (const char*)itoa(pid) + " not transferring");
+ ? Respond(220, "Filter %d stopped", pid)
+ : Respond(560, "Filter %d not transferring", pid);
#else
return Respond(500, "DELF known but unimplemented with VDR < 1.3.0");
#endif
}
-bool cConnectionVTP::CmdABRT(char *Opts) {
+bool cConnectionVTP::CmdABRT(char *Opts)
+{
uint id;
char *ep;
@@ -273,23 +760,22 @@ bool cConnectionVTP::CmdABRT(char *Opts) {
if (ep == Opts || (*ep != '\0' && *ep != ' '))
return Respond(500, "Use: ABRT Id");
- cTimeMs starttime;
- if (id == siLive)
- DELETENULL(m_LiveStreamer);
+ switch (id) {
+ case 0: DELETENULL(m_LiveStreamer); break;
+ }
- Dprintf("ABRT took %ld ms\n", starttime.Elapsed());
- DELETENULL(m_DataSockets[id]);
+ DELETENULL(m_LiveSocket);
return Respond(220, "Data connection closed");
}
-bool cConnectionVTP::CmdQUIT(char *Opts) {
- if (!Respond(221, "Video Disk Recorder closing connection"))
- return false;
+bool cConnectionVTP::CmdQUIT(char *Opts)
+{
DeferClose();
- return true;
+ return Respond(221, "Video Disk Recorder closing connection");
}
-bool cConnectionVTP::CmdSUSP(char *Opts) {
+bool cConnectionVTP::CmdSUSP(char *Opts)
+{
if (StreamdevServerSetup.SuspendMode == smAlways || cSuspendCtl::IsActive())
return Respond(220, "Server is suspended");
else if (StreamdevServerSetup.SuspendMode == smOffer
@@ -300,56 +786,124 @@ bool cConnectionVTP::CmdSUSP(char *Opts) {
return Respond(550, "Client may not suspend server");
}
+// Functions extended from SVDRP
+
+template<class cHandler>
+bool cConnectionVTP::CmdLSTX(cHandler *&Handler, char *Option)
+{
+ if (Option != NULL) {
+ delete Handler;
+ Handler = new cHandler(this, Option);
+ }
+
+ bool last, result = Handler->Next(last);
+ if (!result || last)
+ DELETENULL(Handler);
+
+ return result;
+}
+
+bool cConnectionVTP::CmdLSTE(char *Option)
+{
+ return CmdLSTX(m_LSTEHandler, Option);
+}
+
+bool cConnectionVTP::CmdLSTC(char *Option)
+{
+ return CmdLSTX(m_LSTCHandler, Option);
+}
+
+bool cConnectionVTP::CmdLSTT(char *Option)
+{
+ return CmdLSTX(m_LSTTHandler, Option);
+}
+
// Functions adopted from SVDRP
-#define INIT_WRAPPER() bool _res = true
-#define Reply(x...) _res &= ReplyWrapper(x)
+#define INIT_WRAPPER() bool _res
+#define Reply(c,m...) _res = Respond(c,m)
#define EXIT_WRAPPER() return _res
-bool cConnectionVTP::ReplyWrapper(int Code, const char *fmt, ...) {
- va_list ap;
- va_start(ap, fmt);
- char *buffer;
- vasprintf(&buffer, fmt, ap);
- int npos;
- if (buffer[npos = strlen(buffer)-1] == '\n')
- buffer[npos] = '\0';
- bool res = Respond(Code, buffer);
- free(buffer);
- return res;
+bool cConnectionVTP::CmdMODT(const char *Option)
+{
+ INIT_WRAPPER();
+ if (*Option) {
+ char *tail;
+ int n = strtol(Option, &tail, 10);
+ if (tail && tail != Option) {
+ tail = skipspace(tail);
+ cTimer *timer = Timers.Get(n - 1);
+ if (timer) {
+ cTimer t = *timer;
+ if (strcasecmp(tail, "ON") == 0)
+ t.SetFlags(tfActive);
+ else if (strcasecmp(tail, "OFF") == 0)
+ t.ClrFlags(tfActive);
+ else if (!t.Parse(tail)) {
+ Reply(501, "Error in timer settings");
+ EXIT_WRAPPER();
+ }
+ *timer = t;
+ Timers.SetModified();
+ isyslog("timer %s modified (%s)", *timer->ToDescr(),
+ timer->HasFlags(tfActive) ? "active" : "inactive");
+ Reply(250, "%d %s", timer->Index() + 1, *timer->ToText());
+ } else
+ Reply(501, "Timer \"%d\" not defined", n);
+ } else
+ Reply(501, "Error in timer number");
+ } else
+ Reply(501, "Missing timer settings");
+ EXIT_WRAPPER();
}
-bool cConnectionVTP::CmdLSTE(char *Option) {
-#if VDRVERSNUM < 10300
- cMutexLock MutexLock;
-#else
- cSchedulesLock MutexLock;
-#endif
+bool cConnectionVTP::CmdNEWT(const char *Option)
+{
INIT_WRAPPER();
- /* we need to create a blocking copy of the socket here */
- int dupfd = dup(*this);
- fcntl(dupfd, F_SETFL, fcntl(dupfd, F_GETFL) & ~O_NONBLOCK);
-#if VDRVERSNUM < 10300
- const cSchedules *Schedules = cSIProcessor::Schedules(MutexLock);
-#else
- const cSchedules *Schedules = cSchedules::Schedules(MutexLock);
-#endif
- if (Schedules) {
- FILE *f = fdopen(dupfd, "w");
- if (f) {
- Schedules->Dump(f, "215-");
- fflush(f);
- Reply(215, "End of EPG data");
- fclose(f);
- }
- else
- Reply(451, "Can't open file connection");
- }
- else
- Reply(451, "Can't get EPG data");
+ if (*Option) {
+ cTimer *timer = new cTimer;
+ if (timer->Parse(Option)) {
+ cTimer *t = Timers.GetTimer(timer);
+ if (!t) {
+ Timers.Add(timer);
+ Timers.SetModified();
+ isyslog("timer %s added", *timer->ToDescr());
+ Reply(250, "%d %s", timer->Index() + 1, *timer->ToText());
+ EXIT_WRAPPER();
+ } else
+ Reply(550, "Timer already defined: %d %s", t->Index() + 1,
+ *t->ToText());
+ } else
+ Reply(501, "Error in timer settings");
+ delete timer;
+ } else
+ Reply(501, "Missing timer settings");
+ EXIT_WRAPPER();
+}
+
+bool cConnectionVTP::CmdDELT(const char *Option)
+{
+ INIT_WRAPPER();
+ if (*Option) {
+ if (isnumber(Option)) {
+ cTimer *timer = Timers.Get(strtol(Option, NULL, 10) - 1);
+ if (timer) {
+ if (!timer->Recording()) {
+ isyslog("deleting timer %s", *timer->ToDescr());
+ Timers.Del(timer);
+ Timers.SetModified();
+ Reply(250, "Timer \"%s\" deleted", Option);
+ } else
+ Reply(550, "Timer \"%s\" is recording", Option);
+ } else
+ Reply(501, "Timer \"%s\" not defined", Option);
+ } else
+ Reply(501, "Error in timer number \"%s\"", Option);
+ } else
+ Reply(501, "Missing timer number");
EXIT_WRAPPER();
}
-bool cConnectionVTP::CmdLSTR(char *Option) {
+/*bool cConnectionVTP::CmdLSTR(char *Option) {
INIT_WRAPPER();
bool recordings = Recordings.Load();
Recordings.Sort();
@@ -403,140 +957,23 @@ bool cConnectionVTP::CmdDELR(char *Option) {
else
Reply(501, "Missing recording number");
EXIT_WRAPPER();
-}
-
-bool cConnectionVTP::CmdLSTT(char *Option) {
- INIT_WRAPPER();
- if (*Option) {
- if (isnumber(Option)) {
- cTimer *timer = Timers.Get(strtol(Option, NULL, 10) - 1);
- if (timer)
- Reply(250, "%d %s", timer->Index() + 1, (const char*)timer->ToText(true));
- else
- Reply(501, "Timer \"%s\" not defined", Option);
- }
- else
- Reply(501, "Error in timer number \"%s\"", Option);
- }
- else if (Timers.Count()) {
- for (int i = 0; i < Timers.Count(); i++) {
- cTimer *timer = Timers.Get(i);
- if (timer)
- Reply(i < Timers.Count() - 1 ? -250 : 250, "%d %s", timer->Index() + 1, (const char*)timer->ToText(true));
- else
- Reply(501, "Timer \"%d\" not found", i + 1);
- }
- }
- else
- Reply(550, "No timers defined");
- EXIT_WRAPPER();
-}
+}*/
-bool cConnectionVTP::CmdMODT(char *Option) {
- INIT_WRAPPER();
- if (*Option) {
- char *tail;
- int n = strtol(Option, &tail, 10);
- if (tail && tail != Option) {
- tail = skipspace(tail);
- cTimer *timer = Timers.Get(n - 1);
- if (timer) {
- cTimer t = *timer;
- if (strcasecmp(tail, "ON") == 0)
-#if VDRVERSNUM < 10300
- t.SetActive(taActive);
-#else
- t.SetFlags(tfActive);
-#endif
- else if (strcasecmp(tail, "OFF") == 0)
-#if VDRVERSNUM < 10300
- t.SetActive(taInactive);
-#else
- t.ClrFlags(tfActive);
-#endif
- else if (!t.Parse(tail)) {
- Reply(501, "Error in timer settings");
- EXIT_WRAPPER();
- }
- *timer = t;
- Timers.Save();
-#if VDRVERSNUM < 10300
- isyslog("timer %d modified (%s)", timer->Index() + 1,
- timer->Active() ? "active" : "inactive");
-#else
- isyslog("timer %d modified (%s)", timer->Index() + 1,
- timer->HasFlags(tfActive) ? "active" : "inactive");
-#endif
- Reply(250, "%d %s", timer->Index() + 1, (const char*)timer->ToText(true));
- }
- else
- Reply(501, "Timer \"%d\" not defined", n);
- }
- else
- Reply(501, "Error in timer number");
- }
- else
- Reply(501, "Missing timer settings");
- EXIT_WRAPPER();
-}
-
-bool cConnectionVTP::CmdNEWT(char *Option) {
- INIT_WRAPPER();
- if (*Option) {
- cTimer *timer = new cTimer;
- if (timer->Parse(Option)) {
- cTimer *t = Timers.GetTimer(timer);
- if (!t) {
- Timers.Add(timer);
- Timers.Save();
- isyslog("timer %d added", timer->Index() + 1);
- Reply(250, "%d %s", timer->Index() + 1, (const char*)timer->ToText(true));
- EXIT_WRAPPER();
- }
- else
- Reply(550, "Timer already defined: %d %s", t->Index() + 1, (const char*)t->ToText(true));
- }
- else
- Reply(501, "Error in timer settings");
- delete timer;
- }
- else
- Reply(501, "Missing timer settings");
- EXIT_WRAPPER();
-}
-
-bool cConnectionVTP::CmdDELT(char *Option) {
- INIT_WRAPPER();
- if (*Option) {
- if (isnumber(Option)) {
- cTimer *timer = Timers.Get(strtol(Option, NULL, 10) - 1);
- if (timer) {
- if (!timer->Recording()) {
- Timers.Del(timer);
- Timers.Save();
- isyslog("timer %s deleted", Option);
- Reply(250, "Timer \"%s\" deleted", Option);
- }
- else
- Reply(550, "Timer \"%s\" is recording", Option);
- }
- else
- Reply(501, "Timer \"%s\" not defined", Option);
- }
- else
- Reply(501, "Error in timer number \"%s\"", Option);
- }
- else
- Reply(501, "Missing timer number");
- EXIT_WRAPPER();
-}
-
-bool cConnectionVTP::Respond(int Code, const std::string &Message) {
+bool cConnectionVTP::Respond(int Code, const char *Message, ...)
+{
char *buffer;
- bool result;
- asprintf(&buffer, "%03d%c%s", Code < 0 ? -Code : Code, Code < 0 ? '-' : ' ', Message.c_str());
- result = cServerConnection::Respond(buffer);
- free(buffer);
- return result;
+ va_list ap;
+ va_start(ap, Message);
+ vasprintf(&buffer, Message, ap);
+ va_end(ap);
+ cString str(buffer, true);
+
+ if (Code >= 0 && m_LastCommand != NULL) {
+ free(m_LastCommand);
+ m_LastCommand = NULL;
+ }
+
+ return cServerConnection::Respond("%03d%c%s", Code >= 0,
+ Code < 0 ? -Code : Code,
+ Code < 0 ? '-' : ' ', buffer);
}
-
diff --git a/server/connectionVTP.h b/server/connectionVTP.h
index 4645b65..a0e6a9c 100644
--- a/server/connectionVTP.h
+++ b/server/connectionVTP.h
@@ -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
diff --git a/server/server.c b/server/server.c
index 60f184e..6c54451 100644
--- a/server/server.c
+++ b/server/server.c
@@ -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) {
- m_Active = false;
- Cancel(3);
+void cStreamdevServer::Stop(void)
+{
+ if (m_Active) {
+ 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;
}
diff --git a/server/server.h b/server/server.h
index bf40f37..af574f5 100644
--- a/server/server.h
+++ b/server/server.h
@@ -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;
diff --git a/server/setup.c b/server/setup.c
index bd8fb67..2589fec 100644
--- a/server/setup.c
+++ b/server/setup.c
@@ -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();
}
diff --git a/server/streamer.c b/server/streamer.c
index b64ffdd..582fc6a 100644
--- a/server/streamer.c
+++ b/server/streamer.c
@@ -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;