summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--HISTORY3
-rw-r--r--menu.c4
-rw-r--r--svdrp.c72
-rw-r--r--timers.c94
-rw-r--r--timers.h21
-rw-r--r--vdr.c21
6 files changed, 87 insertions, 128 deletions
diff --git a/HISTORY b/HISTORY
index fec7d18e..2721c151 100644
--- a/HISTORY
+++ b/HISTORY
@@ -9162,7 +9162,7 @@ Video Disk Recorder Revision History
a subdirectory.
- SVDRP peering can now be limited to the default SVDRP host (see MANUAL for details).
-2018-02-20: Version 2.3.9
+2018-02-25: Version 2.3.9
- Updated the Italian OSD texts (thanks to Diego Pierotto).
- Updated the Finnish OSD texts (thanks to Rolf Ahrenberg).
@@ -9283,3 +9283,4 @@ Video Disk Recorder Revision History
SVDRP command CONN instead of using the UDP port with the server's address.
This change requires that all VDRs that shall take part in a peer-to-peer network need
to be updated to this version.
+- Moved handling remote timers into cSVDRPClientHandler::ProcessConnections().
diff --git a/menu.c b/menu.c
index 1759670d..d1eccfca 100644
--- a/menu.c
+++ b/menu.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: menu.c 4.61 2018/02/13 09:25:43 kls Exp $
+ * $Id: menu.c 4.62 2018/02/25 13:07:09 kls Exp $
*/
#include "menu.h"
@@ -4184,7 +4184,7 @@ eOSState cMenuSetupMisc::ProcessKey(eKeys Key)
else {
LOCK_TIMERS_WRITE;
Timers->SetExplicitModify();
- if (Timers->DelRemoteTimers())
+ if (Timers->StoreRemoteTimers(NULL, NULL))
Timers->SetModified();
}
}
diff --git a/svdrp.c b/svdrp.c
index b89bdf1d..48df03ca 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 4.27 2018/02/20 13:28:04 kls Exp $
+ * $Id: svdrp.c 4.28 2018/02/25 13:26:17 kls Exp $
*/
#include "svdrp.h"
@@ -317,6 +317,7 @@ private:
cFile file;
int fetchFlags;
bool connected;
+ bool Send(const char *Command);
void Close(void);
public:
cSVDRPClient(const char *Address, int Port, const char *ServerName, int Timeout);
@@ -324,12 +325,12 @@ public:
const char *ServerName(void) const { return serverName; }
const char *Connection(void) const { return serverIpAddress.Connection(); }
bool HasAddress(const char *Address, int Port) const;
- bool Send(const char *Command);
bool Process(cStringList *Response = NULL);
bool Execute(const char *Command, cStringList *Response = NULL);
bool Connected(void) const { return connected; }
void SetFetchFlag(eSvdrpFetchFlags Flag);
bool HasFetchFlag(eSvdrpFetchFlags Flag);
+ bool GetRemoteTimers(cStringList &Response);
};
static cPoller SVDRPClientPoller;
@@ -365,9 +366,6 @@ void cSVDRPClient::Close(void)
SVDRPClientPoller.Del(file, false);
file.Close();
socket.Close();
- LOCK_TIMERS_WRITE;
- if (Timers)
- Timers->DelRemoteTimers(serverName);
}
}
@@ -483,6 +481,14 @@ bool cSVDRPClient::HasFetchFlag(eSvdrpFetchFlags Flag)
return Result;
}
+bool cSVDRPClient::GetRemoteTimers(cStringList &Response)
+{
+ if (HasFetchFlag(sffTimers))
+ return Execute("LSTT ID", &Response);
+ return false;
+}
+
+
// --- cSVDRPServerParams ----------------------------------------------------
class cSVDRPServerParams {
@@ -554,20 +560,21 @@ private:
cMutex mutex;
int tcpPort;
cSocket udpSocket;
+ cStateKey timersStateKey;
cVector<cSVDRPClient *> clientConnections;
+ void SendDiscover(void);
void HandleClientConnection(void);
void ProcessConnections(void);
+ cSVDRPClient *GetClientForServer(const char *ServerName);
protected:
virtual void Action(void);
public:
cSVDRPClientHandler(int TcpPort, int UdpPort);
virtual ~cSVDRPClientHandler();
- void SendDiscover(void);
void AddClient(cSVDRPServerParams &ServerParams, const char *IpAddress);
bool Execute(const char *ServerName, const char *Command, cStringList *Response = NULL);
bool GetServerNames(cStringList *ServerNames, eSvdrpFetchFlags FetchFlags = sffNone);
bool TriggerFetchingTimers(const char *ServerName);
- cSVDRPClient *GetClientForServer(const char *ServerName);
};
static cSVDRPClientHandler *SVDRPClientHandler = NULL;
@@ -575,6 +582,7 @@ static cSVDRPClientHandler *SVDRPClientHandler = NULL;
cSVDRPClientHandler::cSVDRPClientHandler(int TcpPort, int UdpPort)
:cThread("SVDRP client handler", true)
,udpSocket(UdpPort, false)
+,timersStateKey(true)
{
tcpPort = TcpPort;
}
@@ -588,7 +596,6 @@ cSVDRPClientHandler::~cSVDRPClientHandler()
cSVDRPClient *cSVDRPClientHandler::GetClientForServer(const char *ServerName)
{
- cMutexLock MutexLock(&mutex);
for (int i = 0; i < clientConnections.Size(); i++) {
if (strcmp(clientConnections[i]->ServerName(), ServerName) == 0)
return clientConnections[i];
@@ -598,17 +605,36 @@ cSVDRPClient *cSVDRPClientHandler::GetClientForServer(const char *ServerName)
void cSVDRPClientHandler::SendDiscover(void)
{
- cMutexLock MutexLock(&mutex);
cString Dgram = cString::sprintf("SVDRP:discover name:%s port:%d vdrversion:%d apiversion:%d timeout:%d%s", Setup.SVDRPHostName, tcpPort, VDRVERSNUM, APIVERSNUM, Setup.SVDRPTimeout, (Setup.SVDRPPeering == spmOnly && *Setup.SVDRPDefaultHost) ? *cString::sprintf(" host:%s", Setup.SVDRPDefaultHost) : "");
udpSocket.SendDgram(Dgram, udpSocket.Port());
}
void cSVDRPClientHandler::ProcessConnections(void)
{
- cMutexLock MutexLock(&mutex);
+ cString PollTimersCmd;
+ if (cTimers::GetTimersRead(timersStateKey)) {
+ PollTimersCmd = cString::sprintf("POLL %s TIMERS", Setup.SVDRPHostName);
+ timersStateKey.Remove();
+ }
for (int i = 0; i < clientConnections.Size(); i++) {
- if (!clientConnections[i]->Process()) {
- delete clientConnections[i];
+ cSVDRPClient *Client = clientConnections[i];
+ if (Client->Process()) {
+ cStringList RemoteTimers;
+ if (Client->GetRemoteTimers(RemoteTimers)) {
+ cTimers *Timers = cTimers::GetTimersWrite(timersStateKey);
+ bool TimersModified = Timers->StoreRemoteTimers(Client->ServerName(), &RemoteTimers);
+ timersStateKey.Remove(TimersModified);
+ }
+ if (*PollTimersCmd) {
+ if (!Client->Execute(PollTimersCmd))
+ esyslog("ERROR: can't send '%s' to '%s'", *PollTimersCmd, Client->ServerName());
+ }
+ }
+ else {
+ cTimers *Timers = cTimers::GetTimersWrite(timersStateKey);
+ bool TimersModified = Timers->StoreRemoteTimers(Client->ServerName(), NULL);
+ timersStateKey.Remove(TimersModified);
+ delete Client;
clientConnections.Remove(i);
i--;
}
@@ -617,11 +643,10 @@ void cSVDRPClientHandler::ProcessConnections(void)
void cSVDRPClientHandler::AddClient(cSVDRPServerParams &ServerParams, const char *IpAddress)
{
+ cMutexLock MutexLock(&mutex);
for (int i = 0; i < clientConnections.Size(); i++) {
- if (clientConnections[i]->HasAddress(IpAddress, ServerParams.Port())) {
- dsyslog("SVDRP %s < %s connection to '%s' already exists", Setup.SVDRPHostName, clientConnections[i]->Connection(), clientConnections[i]->ServerName());
+ if (clientConnections[i]->HasAddress(IpAddress, ServerParams.Port()))
return;
- }
}
if (Setup.SVDRPPeering == spmOnly && strcmp(ServerParams.Name(), Setup.SVDRPDefaultHost) != 0)
return; // we only want to peer with the default host, but this isn't the default host
@@ -1294,8 +1319,7 @@ void cSVDRPServer::CmdCONN(const char *Option)
if (ServerParams.Ok()) {
clientName = ServerParams.Name();
Reply(250, "OK"); // must finish this transaction before creating the new client
- if (!SVDRPClientHandler->GetClientForServer(ServerParams.Name()))
- SVDRPClientHandler->AddClient(ServerParams, clientIpAddress.Address());
+ SVDRPClientHandler->AddClient(ServerParams, clientIpAddress.Address());
}
else
Reply(501, "Error in server parameters: %s", ServerParams.Error());
@@ -2601,7 +2625,6 @@ void SetSVDRPGrabImageDir(const char *GrabImageDir)
class cSVDRPServerHandler : public cThread {
private:
- cMutex mutex;
bool ready;
cSocket tcpSocket;
cVector<cSVDRPServer *> serverConnections;
@@ -2613,7 +2636,6 @@ public:
cSVDRPServerHandler(int TcpPort);
virtual ~cSVDRPServerHandler();
void WaitUntilReady(void);
- cSVDRPServer *GetServerForClient(const char *ClientName);
};
static cSVDRPServerHandler *SVDRPServerHandler = NULL;
@@ -2641,7 +2663,6 @@ void cSVDRPServerHandler::WaitUntilReady(void)
void cSVDRPServerHandler::ProcessConnections(void)
{
- cMutexLock MutexLock(&mutex);
for (int i = 0; i < serverConnections.Size(); i++) {
if (!serverConnections[i]->Process()) {
delete serverConnections[i];
@@ -2665,7 +2686,6 @@ void cSVDRPServerHandler::Action(void)
ready = true;
while (Running()) {
SVDRPServerPoller.Poll(1000);
- cMutexLock MutexLock(&mutex);
HandleServerConnection();
ProcessConnections();
}
@@ -2674,16 +2694,6 @@ void cSVDRPServerHandler::Action(void)
}
}
-cSVDRPServer *cSVDRPServerHandler::GetServerForClient(const char *ClientName)
-{
- cMutexLock MutexLock(&mutex);
- for (int i = 0; i < serverConnections.Size(); i++) {
- if (serverConnections[i]->ClientName() && strcmp(serverConnections[i]->ClientName(), ClientName) == 0)
- return serverConnections[i];
- }
- return NULL;
-}
-
// --- SVDRP Handler ---------------------------------------------------------
static cMutex SVDRPHandlerMutex;
diff --git a/timers.c b/timers.c
index 9d28f922..9e4c4856 100644
--- a/timers.c
+++ b/timers.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: timers.c 4.14 2017/11/12 13:01:22 kls Exp $
+ * $Id: timers.c 4.15 2018/02/25 13:05:03 kls Exp $
*/
#include "timers.h"
@@ -898,78 +898,48 @@ bool cTimers::DeleteExpired(void)
return TimersModified;
}
-bool cTimers::GetRemoteTimers(const char *ServerName)
+bool cTimers::StoreRemoteTimers(const char *ServerName, const cStringList *RemoteTimers)
{
+ //TODO handle only new/deleted/modified timers?
bool Result = false;
- if (ServerName) {
- Result = DelRemoteTimers(ServerName);
- cStringList Response;
- if (ExecSVDRPCommand(ServerName, "LSTT ID", &Response)) {
- for (int i = 0; i < Response.Size(); i++) {
- const char *s = Response[i];
- int Code = SVDRPCode(s);
- if (Code == 250) {
- if (const char *v = SVDRPValue(s)) {
- int Id = atoi(v);
- while (*v && *v != ' ')
- v++; // skip id
- cTimer *Timer = new cTimer;
- if (Timer->Parse(v)) {
- Timer->SetRemote(ServerName);
- Timer->SetId(Id);
- Add(Timer);
- Result = true;
- }
- else {
- esyslog("ERROR: %s: error in timer settings: %s", ServerName, v);
- delete Timer;
- }
- }
- }
- else if (Code != 550)
- esyslog("ERROR: %s: %s", ServerName, s);
- }
- return Result;
- }
- }
- else {
- cStringList ServerNames;
- if (GetSVDRPServerNames(&ServerNames, sffTimers)) {
- for (int i = 0; i < ServerNames.Size(); i++)
- Result |= GetRemoteTimers(ServerNames[i]);
- }
- }
- return Result;
-}
-
-bool cTimers::DelRemoteTimers(const char *ServerName)
-{
- bool Deleted = false;
+ // Delete old remote timers:
cTimer *Timer = First();
while (Timer) {
cTimer *t = Next(Timer);
if (Timer->Remote() && (!ServerName || strcmp(Timer->Remote(), ServerName) == 0)) {
Del(Timer);
- Deleted = true;
+ Result = true;
}
Timer = t;
}
- return Deleted;
-}
-
-void cTimers::TriggerRemoteTimerPoll(const char *ServerName)
-{
- if (ServerName) {
- if (!ExecSVDRPCommand(ServerName, cString::sprintf("POLL %s TIMERS", Setup.SVDRPHostName)))
- esyslog("ERROR: can't send 'POLL %s TIMERS' to '%s'", Setup.SVDRPHostName, ServerName);
- }
- else {
- cStringList ServerNames;
- if (GetSVDRPServerNames(&ServerNames)) {
- for (int i = 0; i < ServerNames.Size(); i++)
- TriggerRemoteTimerPoll(ServerNames[i]);
- }
+ // Add new remote timers:
+ if (ServerName && RemoteTimers) {
+ for (int i = 0; i < RemoteTimers->Size(); i++) {
+ const char *s = (*RemoteTimers)[i];
+ int Code = SVDRPCode(s);
+ if (Code == 250) {
+ if (const char *v = SVDRPValue(s)) {
+ int Id = atoi(v);
+ while (*v && *v != ' ')
+ v++; // skip id
+ cTimer *Timer = new cTimer;
+ if (Timer->Parse(v)) {
+ Timer->SetRemote(ServerName);
+ Timer->SetId(Id);
+ Add(Timer);
+ Result = true;
+ }
+ else {
+ esyslog("ERROR: %s: error in timer settings: %s", ServerName, v);
+ delete Timer;
+ }
+ }
+ }
+ else if (Code != 550)
+ esyslog("ERROR: %s: %s", ServerName, s);
+ }
}
+ return Result;
}
static bool RemoteTimerError(const cTimer *Timer, cString *Msg)
diff --git a/timers.h b/timers.h
index 18ba30ec..3146fce5 100644
--- a/timers.h
+++ b/timers.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: timers.h 4.9 2017/10/31 09:47:14 kls Exp $
+ * $Id: timers.h 4.10 2018/02/25 12:54:55 kls Exp $
*/
#ifndef __TIMERS_H
@@ -185,21 +185,12 @@ public:
void Add(cTimer *Timer, cTimer *After = NULL);
void Ins(cTimer *Timer, cTimer *Before = NULL);
void Del(cTimer *Timer, bool DeleteObject = true);
- bool GetRemoteTimers(const char *ServerName = NULL);
- ///< Gets the timers from the given remote machine and adds them to this
- ///< list. If no ServerName is given, all timers from all known remote
- ///< machines will be fetched. This function calls DelRemoteTimers() with
- ///< the given ServerName first.
+ bool StoreRemoteTimers(const char *ServerName = NULL, const cStringList *RemoteTimers = NULL);
+ ///< Stores the given list of RemoteTimers, which come from the VDR ServerName, in
+ ///< this list. If no ServerName is given, all remote timers from all peer machines
+ ///< will be removed from this list. If no RemoteTimers are given, only the remote
+ ///< timers from ServerName will be removed from this list.
///< Returns true if any remote timers have been added or deleted
- bool DelRemoteTimers(const char *ServerName = NULL);
- ///< Deletes all timers of the given remote machine from this list (leaves
- ///< them untouched on the remote machine). If no ServerName is given, the
- ///< timers of all remote machines will be deleted from the list.
- ///< Returns true if any remote timers have been deleted.
- void TriggerRemoteTimerPoll(const char *ServerName = NULL);
- ///< Sends an SVDRP POLL command to the given remote machine.
- ///< If no ServerName is given, the POLL command will be sent to all
- ///< known remote machines.
};
bool HandleRemoteTimerModifications(cTimer *NewTimer, cTimer *OldTimer = NULL, cString *Msg = NULL);
diff --git a/vdr.c b/vdr.c
index 78afa872..1e012a2e 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.21 2017/11/09 16:15:34 kls Exp $
+ * $Id: vdr.c 4.22 2018/02/25 13:07:09 kls Exp $
*/
#include <getopt.h>
@@ -1081,25 +1081,18 @@ int main(int argc, char *argv[])
{
// Timers and Recordings:
bool TimersModified = false;
- bool TriggerRemoteTimerPoll = false;
static cStateKey TimersStateKey(true);
- if (cTimers::GetTimersRead(TimersStateKey)) {
- TriggerRemoteTimerPoll = true;
+ if (cTimers::GetTimersRead(TimersStateKey))
TimersStateKey.Remove();
- }
cTimers *Timers = cTimers::GetTimersWrite(TimersStateKey);
- // Get remote timers:
- TimersModified |= Timers->GetRemoteTimers();
// Assign events to timers:
static cStateKey SchedulesStateKey;
if (const cSchedules *Schedules = cSchedules::GetSchedulesRead(SchedulesStateKey))
TimersModified |= Timers->SetEvents(Schedules);
// Must do all following calls with the exact same time!
// Process ongoing recordings:
- if (cRecordControls::Process(Timers, Now)) {
+ if (cRecordControls::Process(Timers, Now))
TimersModified = true;
- TriggerRemoteTimerPoll = true;
- }
// Must keep the lock on the schedules until after processing the record
// controls, in order to avoid short interrupts in case the current event
// is replaced by a new one (which some broadcasters do, instead of just
@@ -1113,7 +1106,6 @@ int main(int argc, char *argv[])
else
LastTimerChannel = Timer->Channel()->Number();
TimersModified = true;
- TriggerRemoteTimerPoll = true;
}
// Make sure timers "see" their channel early enough:
static time_t LastTimerCheck = 0;
@@ -1168,13 +1160,8 @@ int main(int argc, char *argv[])
LastTimerCheck = Now;
}
// Delete expired timers:
- if (Timers->DeleteExpired()) {
+ if (Timers->DeleteExpired())
TimersModified = true;
- TriggerRemoteTimerPoll = true;
- }
- // Trigger remote timer polls:
- if (TriggerRemoteTimerPoll)
- Timers->TriggerRemoteTimerPoll();
// Make sure there is enough free disk space for ongoing recordings:
AssertFreeDiskSpace(Timers->GetMaxPriority());
TimersStateKey.Remove(TimersModified);