summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--HISTORY14
-rw-r--r--interface.c12
-rw-r--r--interface.h7
-rw-r--r--svdrp.c234
-rw-r--r--svdrp.h87
-rw-r--r--vdr.c14
6 files changed, 221 insertions, 147 deletions
diff --git a/HISTORY b/HISTORY
index 373e881f..20a6b682 100644
--- a/HISTORY
+++ b/HISTORY
@@ -8596,7 +8596,7 @@ Video Disk Recorder Revision History
- Bumped all version numbers to 2.2.0.
- Official release.
-2015-04-19: Version 2.3.1
+2015-04-29: Version 2.3.1
- The new function cOsd::MaxPixmapSize() can be called to determine the maximum size
a cPixmap may have on the current OSD. The 'osddemo' example has been modified
@@ -8645,3 +8645,15 @@ Video Disk Recorder Revision History
//#define DEPRECATED_GETBITMAP
in osd.h as a quick workaround. In the long run the plugin will need to be adapted.
- The -u option now also accepts a numerical user id (suggested by Derek Kelly).
+- The SVDRP port now accepts multiple concurrent connections. You can now keep an
+ SVDRP connection open as long as you wish, without preventing others from
+ connecting. Note, though, that SVDRP connections still get closed automatically
+ if there has been no activity for 300 seconds (configurable via
+ "Setup/Miscellaneous/SVDRP timeout (s)").
+- The SVDRP log messages have been unified and now always contain the IP and port
+ number of the remote host.
+- SVDRP connections are now handled in a separate thread, which makes them more
+ responsive. Note that there is only one thread that handles all concurrent SVDRP
+ connections. That way each SVDRP command is guaranteed to be processed separately,
+ without interfering with any other SVDRP commands that might be issued at the same
+ time.
diff --git a/interface.c b/interface.c
index 6bf7ffce..dcb766ca 100644
--- a/interface.c
+++ b/interface.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: interface.c 3.1 2015/01/11 13:37:47 kls Exp $
+ * $Id: interface.c 4.1 2015/04/28 11:16:06 kls Exp $
*/
#include "interface.h"
@@ -19,27 +19,19 @@
cInterface *Interface = NULL;
-cInterface::cInterface(int SVDRPport)
+cInterface::cInterface(void)
{
interrupted = false;
- SVDRP = NULL;
- if (SVDRPport)
- SVDRP = new cSVDRP(SVDRPport);
}
cInterface::~cInterface()
{
- delete SVDRP;
}
eKeys cInterface::GetKey(bool Wait)
{
if (!cRemote::HasKeys())
Skins.Flush();
- if (SVDRP) {
- if (SVDRP->Process())
- Wait = false;
- }
if (!cRemote::IsLearning())
return cRemote::Get(Wait ? 1000 : 10);
else
diff --git a/interface.h b/interface.h
index 2b3f979a..4131cf3a 100644
--- a/interface.h
+++ b/interface.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: interface.h 1.31 2004/05/01 11:11:13 kls Exp $
+ * $Id: interface.h 4.1 2015/04/28 11:15:11 kls Exp $
*/
#ifndef __INTERFACE_H
@@ -13,17 +13,14 @@
#include "config.h"
#include "remote.h"
#include "skins.h"
-#include "svdrp.h"
class cInterface {
private:
bool interrupted;
- cSVDRP *SVDRP;
bool QueryKeys(cRemote *Remote, cSkinDisplayMenu *DisplayMenu);
public:
- cInterface(int SVDRPport = 0);
+ cInterface(void);
~cInterface();
- bool HasSVDRPConnection(void) { return SVDRP && SVDRP->HasConnection(); }
void Interrupt(void) { interrupted = true; }
eKeys GetKey(bool Wait = true);
eKeys Wait(int Seconds = 0, bool KeepChar = false);
diff --git a/svdrp.c b/svdrp.c
index 2b5edb2c..f249d169 100644
--- a/svdrp.c
+++ b/svdrp.c
@@ -10,7 +10,7 @@
* and interact with the Video Disk Recorder - or write a full featured
* graphical interface that sits on top of an SVDRP connection.
*
- * $Id: svdrp.c 3.6 2015/01/12 11:16:27 kls Exp $
+ * $Id: svdrp.c 4.1 2015/04/29 13:10:01 kls Exp $
*/
#include "svdrp.h"
@@ -33,14 +33,32 @@
#include "keys.h"
#include "menu.h"
#include "plugin.h"
+#include "recording.h"
#include "remote.h"
#include "skins.h"
+#include "thread.h"
#include "timers.h"
#include "tools.h"
#include "videodir.h"
// --- cSocket ---------------------------------------------------------------
+class cSocket {
+private:
+ int port;
+ int sock;
+ int queue;
+ cString lastAcceptedConnection;
+public:
+ cSocket(int Port, int Queue = 1);
+ ~cSocket();
+ bool Open(void);
+ void Close(void);
+ int Socket(void) const { return sock; }
+ int Accept(void);
+ const char *LastAcceptedConnection(void) const { return lastAcceptedConnection; }
+ };
+
cSocket::cSocket(int Port, int Queue)
{
port = Port;
@@ -100,6 +118,7 @@ bool cSocket::Open(void)
LOG_ERROR;
return false;
}
+ isyslog("SVDRP listening on port %d/tcp", port);
}
return true;
}
@@ -110,7 +129,7 @@ int cSocket::Accept(void)
struct sockaddr_in clientname;
uint size = sizeof(clientname);
int newsock = accept(sock, (struct sockaddr *)&clientname, &size);
- if (newsock > 0) {
+ if (newsock >= 0) {
bool accepted = SVDRPhosts.Acceptable(clientname.sin_addr.s_addr);
if (!accepted) {
const char *s = "Access denied!\n";
@@ -119,7 +138,8 @@ int cSocket::Accept(void)
close(newsock);
newsock = -1;
}
- isyslog("connect from %s, port %hu - %s", inet_ntoa(clientname.sin_addr), ntohs(clientname.sin_port), accepted ? "accepted" : "DENIED");
+ lastAcceptedConnection = cString::sprintf("%s:%hu", inet_ntoa(clientname.sin_addr), ntohs(clientname.sin_port));
+ isyslog("SVDRP %s connection %s", *lastAcceptedConnection, accepted ? "accepted" : "DENIED");
}
else if (errno != EINTR && errno != EAGAIN)
LOG_ERROR;
@@ -130,6 +150,19 @@ int cSocket::Accept(void)
// --- cPUTEhandler ----------------------------------------------------------
+class cPUTEhandler {
+private:
+ FILE *f;
+ int status;
+ const char *message;
+public:
+ cPUTEhandler(void);
+ ~cPUTEhandler();
+ bool Process(const char *s);
+ int Status(void) { return status; }
+ const char *Message(void) { return message; }
+ };
+
cPUTEhandler::cPUTEhandler(void)
{
if ((f = tmpfile()) != NULL) {
@@ -385,17 +418,77 @@ const char *GetHelpPage(const char *Cmd, const char **p)
return NULL;
}
-char *cSVDRP::grabImageDir = NULL;
+static cString grabImageDir;
+
+class cSVDRP {
+private:
+ int socket;
+ cString connection;
+ cFile file;
+ cRecordings recordings;
+ cPUTEhandler *PUTEhandler;
+ int numChars;
+ int length;
+ char *cmdLine;
+ time_t lastActivity;
+ void Close(bool SendReply = false, bool Timeout = false);
+ bool Send(const char *s, int length = -1);
+ void Reply(int Code, const char *fmt, ...) __attribute__ ((format (printf, 3, 4)));
+ void PrintHelpTopics(const char **hp);
+ void CmdCHAN(const char *Option);
+ void CmdCLRE(const char *Option);
+ void CmdDELC(const char *Option);
+ void CmdDELR(const char *Option);
+ void CmdDELT(const char *Option);
+ void CmdEDIT(const char *Option);
+ void CmdGRAB(const char *Option);
+ void CmdHELP(const char *Option);
+ void CmdHITK(const char *Option);
+ void CmdLSTC(const char *Option);
+ void CmdLSTE(const char *Option);
+ void CmdLSTR(const char *Option);
+ void CmdLSTT(const char *Option);
+ void CmdMESG(const char *Option);
+ void CmdMODC(const char *Option);
+ void CmdMODT(const char *Option);
+ void CmdMOVC(const char *Option);
+ void CmdMOVR(const char *Option);
+ void CmdNEWC(const char *Option);
+ void CmdNEWT(const char *Option);
+ void CmdNEXT(const char *Option);
+ void CmdPLAY(const char *Option);
+ void CmdPLUG(const char *Option);
+ void CmdPUTE(const char *Option);
+ void CmdREMO(const char *Option);
+ void CmdSCAN(const char *Option);
+ void CmdSTAT(const char *Option);
+ void CmdUPDT(const char *Option);
+ void CmdUPDR(const char *Option);
+ void CmdVOLU(const char *Option);
+ void Execute(char *Cmd);
+public:
+ cSVDRP(int Socket, const char *Connection);
+ ~cSVDRP();
+ bool HasConnection(void) { return file.IsOpen(); }
+ bool Process(void);
+ };
-cSVDRP::cSVDRP(int Port)
-:socket(Port)
+cSVDRP::cSVDRP(int Socket, const char *Connection)
{
+ socket = Socket;
+ connection = Connection;
PUTEhandler = NULL;
numChars = 0;
length = BUFSIZ;
cmdLine = MALLOC(char, length);
- lastActivity = 0;
- isyslog("SVDRP listening on port %d", Port);
+ lastActivity = time(NULL);
+ if (file.Open(socket)) {
+ //TODO how can we get the *full* hostname?
+ char buffer[BUFSIZ];
+ gethostname(buffer, sizeof(buffer));
+ time_t now = time(NULL);
+ Reply(220, "%s SVDRP VideoDiskRecorder %s; %s; %s", buffer, VDRVERSION, *TimeToString(now), cCharSetConv::SystemCharacterTable() ? cCharSetConv::SystemCharacterTable() : "UTF-8");
+ }
}
cSVDRP::~cSVDRP()
@@ -413,10 +506,11 @@ void cSVDRP::Close(bool SendReply, bool Timeout)
gethostname(buffer, sizeof(buffer));
Reply(221, "%s closing connection%s", buffer, Timeout ? " (timeout)" : "");
}
- isyslog("closing SVDRP connection"); //TODO store IP#???
+ isyslog("SVDRP %s connection closed", *connection);
file.Close();
DELETENULL(PUTEhandler);
}
+ close(socket);
}
bool cSVDRP::Send(const char *s, int length)
@@ -454,7 +548,7 @@ void cSVDRP::Reply(int Code, const char *fmt, ...)
}
else {
Reply(451, "Zero return code - looks like a programming error!");
- esyslog("SVDRP: zero return code!");
+ esyslog("SVDRP %s zero return code!", *connection);
}
}
}
@@ -641,7 +735,7 @@ void cSVDRP::CmdDELC(const char *Option)
Channels.Del(channel);
Channels.ReNumber();
Channels.SetModified(true);
- isyslog("channel %s deleted", Option);
+ isyslog("SVDRP %s channel %s deleted", *connection, Option);
if (CurrentChannel && CurrentChannel->Number() != CurrentChannelNr) {
if (!cDevice::PrimaryDevice()->Replaying() || cDevice::PrimaryDevice()->Transferring())
Channels.SwitchTo(CurrentChannel->Number());
@@ -714,7 +808,7 @@ void cSVDRP::CmdDELT(const char *Option)
cTimer *timer = Timers.Get(strtol(Option, NULL, 10) - 1);
if (timer) {
if (!timer->Recording()) {
- isyslog("deleting timer %s", *timer->ToDescr());
+ isyslog("SVDRP %s deleting timer %s", *connection, *timer->ToDescr());
Timers.Del(timer);
Timers.SetModified();
Reply(250, "Timer \"%s\" deleted", Option);
@@ -831,7 +925,7 @@ void cSVDRP::CmdGRAB(const char *Option)
// canonicalize the file name:
char RealFileName[PATH_MAX];
if (FileName) {
- if (grabImageDir) {
+ if (*grabImageDir) {
cString s(FileName);
FileName = s;
const char *slash = strrchr(FileName, '/');
@@ -868,7 +962,7 @@ void cSVDRP::CmdGRAB(const char *Option)
int fd = open(FileName, O_WRONLY | O_CREAT | O_NOFOLLOW | O_TRUNC, DEFFILEMODE);
if (fd >= 0) {
if (safe_write(fd, Image, ImageSize) == ImageSize) {
- dsyslog("grabbed image to %s", FileName);
+ dsyslog("SVDRP %s grabbed image to %s", *connection, FileName);
Reply(250, "Grabbed image %s", Option);
}
else {
@@ -1195,7 +1289,7 @@ void cSVDRP::CmdLSTT(const char *Option)
void cSVDRP::CmdMESG(const char *Option)
{
if (*Option) {
- isyslog("SVDRP message: '%s'", Option);
+ isyslog("SVDRP %s message '%s'", *connection, Option);
Skins.QueueMessage(mtInfo, Option);
Reply(250, "Message queued");
}
@@ -1219,7 +1313,7 @@ void cSVDRP::CmdMODC(const char *Option)
*channel = ch;
Channels.ReNumber();
Channels.SetModified(true);
- isyslog("modifed channel %d %s", channel->Number(), *channel->ToText());
+ isyslog("SVDRP %s modifed channel %d %s", *connection, channel->Number(), *channel->ToText());
Reply(250, "%d %s", channel->Number(), *channel->ToText());
}
else
@@ -1262,7 +1356,7 @@ void cSVDRP::CmdMODT(const char *Option)
}
*timer = t;
Timers.SetModified();
- isyslog("timer %s modified (%s)", *timer->ToDescr(), timer->HasFlags(tfActive) ? "active" : "inactive");
+ isyslog("SVDRP %s timer %s modified (%s)", *connection, *timer->ToDescr(), timer->HasFlags(tfActive) ? "active" : "inactive");
Reply(250, "%d %s", timer->Index() + 1, *timer->ToText());
}
else
@@ -1306,7 +1400,7 @@ void cSVDRP::CmdMOVC(const char *Option)
else
cDevice::SetCurrentChannel(CurrentChannel);
}
- isyslog("channel %d moved to %d", FromNumber, ToNumber);
+ isyslog("SVDRP %s channel %d moved to %d", *connection, FromNumber, ToNumber);
Reply(250,"Channel \"%d\" moved to \"%d\"", From, To);
}
else
@@ -1382,7 +1476,7 @@ void cSVDRP::CmdNEWC(const char *Option)
Channels.Add(channel);
Channels.ReNumber();
Channels.SetModified(true);
- isyslog("new channel %d %s", channel->Number(), *channel->ToText());
+ isyslog("SVDRP %s new channel %d %s", *connection, channel->Number(), *channel->ToText());
Reply(250, "%d %s", channel->Number(), *channel->ToText());
}
else
@@ -1402,7 +1496,7 @@ void cSVDRP::CmdNEWT(const char *Option)
if (timer->Parse(Option)) {
Timers.Add(timer);
Timers.SetModified();
- isyslog("timer %s added", *timer->ToDescr());
+ isyslog("SVDRP %s timer %s added", *connection, *timer->ToDescr());
Reply(250, "%d %s", timer->Index() + 1, *timer->ToText());
return;
}
@@ -1622,11 +1716,11 @@ void cSVDRP::CmdUPDT(const char *Option)
t->Parse(Option);
delete timer;
timer = t;
- isyslog("timer %s updated", *timer->ToDescr());
+ isyslog("SVDRP %s timer %s updated", *connection, *timer->ToDescr());
}
else {
Timers.Add(timer);
- isyslog("timer %s added", *timer->ToDescr());
+ isyslog("SVDRP %s timer %s added", *connection, *timer->ToDescr());
}
Timers.SetModified();
Reply(250, "%d %s", timer->Index() + 1, *timer->ToText());
@@ -1729,19 +1823,7 @@ void cSVDRP::Execute(char *Cmd)
bool cSVDRP::Process(void)
{
- bool NewConnection = !file.IsOpen();
- bool SendGreeting = NewConnection;
-
- if (file.IsOpen() || file.Open(socket.Accept())) {
- if (SendGreeting) {
- //TODO how can we get the *full* hostname?
- char buffer[BUFSIZ];
- gethostname(buffer, sizeof(buffer));
- time_t now = time(NULL);
- Reply(220, "%s SVDRP VideoDiskRecorder %s; %s; %s", buffer, VDRVERSION, *TimeToString(now), cCharSetConv::SystemCharacterTable() ? cCharSetConv::SystemCharacterTable() : "UTF-8");
- }
- if (NewConnection)
- lastActivity = time(NULL);
+ if (file.IsOpen()) {
while (file.Ready(false)) {
unsigned char c;
int r = safe_read(file, &c, 1);
@@ -1781,7 +1863,7 @@ bool cSVDRP::Process(void)
cmdLine = NewBuffer;
}
else {
- esyslog("ERROR: out of memory");
+ esyslog("SVDRP %s ERROR: out of memory", *connection);
Close();
break;
}
@@ -1792,23 +1874,87 @@ bool cSVDRP::Process(void)
lastActivity = time(NULL);
}
else if (r <= 0) {
- isyslog("lost connection to SVDRP client");
+ isyslog("SVDRP %s lost connection to client", *connection);
Close();
}
}
if (Setup.SVDRPTimeout && time(NULL) - lastActivity > Setup.SVDRPTimeout) {
- isyslog("timeout on SVDRP connection");
+ isyslog("SVDRP %s timeout on connection", *connection);
Close(true, true);
}
- return true;
}
- return false;
+ return file.IsOpen();
+}
+
+void SetSVDRPGrabImageDir(const char *GrabImageDir)
+{
+ grabImageDir = GrabImageDir;
+}
+
+// --- cSVDRPHandler ---------------------------------------------------------
+
+class cSVDRPHandler : public cThread {
+private:
+ cSocket socket;
+ cVector<cSVDRP *> connections;
+ void ProcessConnections(void);
+protected:
+ virtual void Action(void);
+public:
+ cSVDRPHandler(int Port);
+ virtual ~cSVDRPHandler();
+ };
+
+cSVDRPHandler::cSVDRPHandler(int Port)
+:cThread("SVDRP handler", true)
+,socket(Port)
+{
+}
+
+cSVDRPHandler::~cSVDRPHandler()
+{
+ Cancel(3);
+}
+
+void cSVDRPHandler::ProcessConnections(void)
+{
+ for (int i = 0; i < connections.Size(); i++) {
+ if (connections[i]) {
+ if (!connections[i]->Process()) {
+ delete connections[i];
+ connections.Remove(i);
+ i--;
+ }
+ }
+ }
+}
+
+void cSVDRPHandler::Action(void)
+{
+ if (socket.Open()) {
+ while (Running()) {
+ cFile::AnyFileReady(socket.Socket(), 1000);
+ int NewSocket = socket.Accept();
+ if (NewSocket >= 0)
+ connections.Append(new cSVDRP(NewSocket, socket.LastAcceptedConnection()));
+ ProcessConnections();
+ }
+ socket.Close();
+ }
}
-void cSVDRP::SetGrabImageDir(const char *GrabImageDir)
+static cSVDRPHandler *SVDRPHandler = NULL;
+
+void StartSVDRPHandler(int Port)
{
- free(grabImageDir);
- grabImageDir = GrabImageDir ? strdup(GrabImageDir) : NULL;
+ if (Port && !SVDRPHandler) {
+ SVDRPHandler = new cSVDRPHandler(Port);
+ SVDRPHandler->Start();
+ }
}
-//TODO more than one connection???
+void StopSVDRPHandler(void)
+{
+ delete SVDRPHandler;
+ SVDRPHandler = NULL;
+}
diff --git a/svdrp.h b/svdrp.h
index 8ac419af..2b426ed6 100644
--- a/svdrp.h
+++ b/svdrp.h
@@ -4,93 +4,14 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: svdrp.h 3.2 2013/10/21 07:42:03 kls Exp $
+ * $Id: svdrp.h 4.1 2015/04/29 13:10:06 kls Exp $
*/
#ifndef __SVDRP_H
#define __SVDRP_H
-#include "recording.h"
-#include "tools.h"
-
-class cSocket {
-private:
- int port;
- int sock;
- int queue;
- void Close(void);
-public:
- cSocket(int Port, int Queue = 1);
- ~cSocket();
- bool Open(void);
- int Accept(void);
- };
-
-class cPUTEhandler {
-private:
- FILE *f;
- int status;
- const char *message;
-public:
- cPUTEhandler(void);
- ~cPUTEhandler();
- bool Process(const char *s);
- int Status(void) { return status; }
- const char *Message(void) { return message; }
- };
-
-class cSVDRP {
-private:
- cSocket socket;
- cFile file;
- cRecordings recordings;
- cPUTEhandler *PUTEhandler;
- int numChars;
- int length;
- char *cmdLine;
- time_t lastActivity;
- static char *grabImageDir;
- void Close(bool SendReply = false, bool Timeout = false);
- bool Send(const char *s, int length = -1);
- void Reply(int Code, const char *fmt, ...) __attribute__ ((format (printf, 3, 4)));
- void PrintHelpTopics(const char **hp);
- void CmdCHAN(const char *Option);
- void CmdCLRE(const char *Option);
- void CmdDELC(const char *Option);
- void CmdDELR(const char *Option);
- void CmdDELT(const char *Option);
- void CmdEDIT(const char *Option);
- void CmdGRAB(const char *Option);
- void CmdHELP(const char *Option);
- void CmdHITK(const char *Option);
- void CmdLSTC(const char *Option);
- void CmdLSTE(const char *Option);
- void CmdLSTR(const char *Option);
- void CmdLSTT(const char *Option);
- void CmdMESG(const char *Option);
- void CmdMODC(const char *Option);
- void CmdMODT(const char *Option);
- void CmdMOVC(const char *Option);
- void CmdMOVR(const char *Option);
- void CmdNEWC(const char *Option);
- void CmdNEWT(const char *Option);
- void CmdNEXT(const char *Option);
- void CmdPLAY(const char *Option);
- void CmdPLUG(const char *Option);
- void CmdPUTE(const char *Option);
- void CmdREMO(const char *Option);
- void CmdSCAN(const char *Option);
- void CmdSTAT(const char *Option);
- void CmdUPDT(const char *Option);
- void CmdUPDR(const char *Option);
- void CmdVOLU(const char *Option);
- void Execute(char *Cmd);
-public:
- cSVDRP(int Port);
- ~cSVDRP();
- bool HasConnection(void) { return file.IsOpen(); }
- bool Process(void);
- static void SetGrabImageDir(const char *GrabImageDir);
- };
+void SetSVDRPGrabImageDir(const char *GrabImageDir);
+void StartSVDRPHandler(int Port);
+void StopSVDRPHandler(void);
#endif //__SVDRP_H
diff --git a/vdr.c b/vdr.c
index d8b2b1a5..c196f8a3 100644
--- a/vdr.c
+++ b/vdr.c
@@ -22,7 +22,7 @@
*
* The project's page is at http://www.tvdr.de
*
- * $Id: vdr.c 4.2 2015/04/19 12:38:12 kls Exp $
+ * $Id: vdr.c 4.3 2015/04/29 09:18:54 kls Exp $
*/
#include <getopt.h>
@@ -65,6 +65,7 @@
#include "sourceparams.h"
#include "sources.h"
#include "status.h"
+#include "svdrp.h"
#include "themes.h"
#include "timers.h"
#include "tools.h"
@@ -375,7 +376,7 @@ int main(int argc, char *argv[])
break;
case 'g' | 0x100:
return GenerateIndex(optarg) ? 0 : 2;
- case 'g': cSVDRP::SetGrabImageDir(*optarg != '-' ? optarg : NULL);
+ case 'g': SetSVDRPGrabImageDir(*optarg != '-' ? optarg : NULL);
break;
case 'h': DisplayHelp = true;
break;
@@ -831,7 +832,7 @@ int main(int argc, char *argv[])
// User interface:
- Interface = new cInterface(SVDRPport);
+ Interface = new cInterface;
// Default skins:
@@ -913,6 +914,10 @@ int main(int argc, char *argv[])
sd_notify(0, "READY=1\nSTATUS=Ready");
#endif
+ // SVDRP:
+
+ StartSVDRPHandler(SVDRPport);
+
// Main program loop:
#define DELETE_MENU ((IsInfoMenu &= (Menu == NULL)), delete Menu, Menu = NULL)
@@ -1418,7 +1423,7 @@ int main(int argc, char *argv[])
// Keep the recordings handler alive:
RecordingsHandler.Active();
- if ((Now - LastInteract) > ACTIVITYTIMEOUT && !cRecordControls::Active() && !RecordingsHandler.Active() && !Interface->HasSVDRPConnection() && (Now - cRemote::LastActivity()) > ACTIVITYTIMEOUT) {
+ if ((Now - LastInteract) > ACTIVITYTIMEOUT && !cRecordControls::Active() && !RecordingsHandler.Active() && (Now - cRemote::LastActivity()) > ACTIVITYTIMEOUT) {
// Handle housekeeping tasks
// Shutdown:
@@ -1466,6 +1471,7 @@ Exit:
signal(SIGPIPE, SIG_DFL);
signal(SIGALRM, SIG_DFL);
+ StopSVDRPHandler();
PluginManager.StopPlugins();
cRecordControls::Shutdown();
RecordingsHandler.DelAll();