Implemented SVDRP peering

This commit is contained in:
Klaus Schmidinger 2015-05-22 13:44:43 +02:00
parent 2b9e988dd5
commit c3b0347556
7 changed files with 840 additions and 170 deletions

24
HISTORY
View File

@ -8652,8 +8652,22 @@ Video Disk Recorder Revision History
"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.
- SVDRP connections are now handled in a separate "SVDRP server handler" 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. Plugins that implement SVDRP commands may need to take
care of proper locking if the commands access global data.
- VDR now sends out a broadcast to port 6419/udp, which was assigned to 'svdrp-disc'
by the IANA. VDRs listening on that port will automatically initiate an SVDRP
connection to the broadcasting VDR, and in turn send out a broadcast to make
other VDRs connect to them. That way all VDRs within the local network will
have permanent "peer-to-peer" SVDRP connections between each other. The
configuration in the svdrphosts.conf file is taken into account when considering
whether or not to respond to an SVDRP discover broadcast.
- The new SVDRP command PING is used by automatically established peer-to-peer
connections to keep them alive.
- The new function GetSVDRPServerNames() can be used to get a list of all VDRs
this VDR is connected to via SVDRP.
- The new class cSVDRPCommand can be used to execute an SVDRP command on one of
the servers this VDR is connected to, and retrieve the result.

View File

@ -38,7 +38,7 @@ Copyright &copy; 2015 Klaus Schmidinger<br>
<a href="http://www.tvdr.de">www.tvdr.de</a>
</div>
<div class="center">
<modified>Important modifications introduced since version 2.0 are marked like this.</modified>
<modified>Important modifications introduced since version 2.2 are marked like this.</modified>
</div>
<p>
VDR provides an easy to use plugin interface that allows additional functionality
@ -99,12 +99,12 @@ structures and allows it to hook itself into specific areas to perform special a
<li><a href="#Skins">Skins</a>
<li><a href="#Themes">Themes</a>
<li><a href="#Devices">Devices</a>
<li><modified><a href="#Positioners">Positioners</a></modified>
<li><a href="#Positioners">Positioners</a>
<li><a href="#Audio">Audio</a>
<li><a href="#Remote Control">Remote Control</a>
<li><a href="#Conditional Access">Conditional Access</a>
<li><a href="#Electronic Program Guide">Electronic Program Guide</a>
<li><modified><a href="#The video directory">The video directory</a></modified>
<li><a href="#The video directory">The video directory</a>
</ul>
</ul>
@ -1161,6 +1161,12 @@ The returned string may consist of several lines, separated by the newline chara
('<tt>\n</tt>'). Each of these lines will be preceded with the <tt>ReplyCode</tt>
when presenting them to the caller, and the continuation character ('<tt>-</tt>')
will be set for all but the last one.
<p>
<modified>
<b>The SVDRP functions are called from the separate "SVDRP server handler" thread.
Therefore the plugin needs to take care of proper locking if it accesses any
global data.</b>
</modified>
<hr><h2><a name="Loading plugins into VDR">Loading plugins into VDR</a></h2>
@ -1877,7 +1883,7 @@ virtual bool SetPlayMode(ePlayMode PlayMode);
virtual int64_t GetSTC(void);
virtual bool IsPlayingVideo(void) const;
virtual bool HasIBPTrickSpeed(void);
virtual void TrickSpeed(int Speed<modified>, bool Forward</modified>);
virtual void TrickSpeed(int Speed, bool Forward);
virtual void Clear(void);
virtual void Play(void);
virtual void Freeze(void);
@ -2026,7 +2032,6 @@ new cMyDeviceHook;
and shall not delete this object. It will be automatically deleted when the program ends.
<div class="modified">
<hr><h2><a name="Positioners">Positioners</a></h2>
<div class="blurb">Now you see me - now you don't!</div><p>
@ -2065,7 +2070,6 @@ You should create your derived positioner object in the
Note that the object has to be created on the heap (using <tt>new</tt>),
and you shall not delete it at any point (it will be deleted automatically
when the program ends).
</div modified>
<hr><h2><a name="Audio">Audio</a></h2>
@ -2301,7 +2305,6 @@ to signal VDR that no other EPG handlers shall be queried after this one.
<p>
See <tt>VDR/epg.h</tt> for details.
<div class="modified">
<hr><h2><a name="The video directory">The video directory</a></h2>
<div class="blurb">Bits and pieces...</div><p>
@ -2335,7 +2338,6 @@ You should create your derived video directory object in the
Note that the object has to be created on the heap (using <tt>new</tt>),
and you shall not delete it at any point (it will be deleted automatically
when the program ends).
</div modified>
</body>
</html>

856
svdrp.c

File diff suppressed because it is too large Load Diff

46
svdrp.h
View File

@ -4,14 +4,56 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: svdrp.h 4.1 2015/04/29 13:10:06 kls Exp $
* $Id: svdrp.h 4.2 2015/05/22 13:44:43 kls Exp $
*/
#ifndef __SVDRP_H
#define __SVDRP_H
#include "tools.h"
class cSVDRPCommand {
protected:
cString serverName;
cString command;
cStringList response;
public:
cSVDRPCommand(const char *ServerName, const char *Command);
///< Sets up an SVDRP Command to be executed on the VDR with the given
///< ServerName. A list of all available servers can be retrieved by
///< calling GetSVDRPServerNames().
///< Command is one SVDRP command, followed by optional parameters,
///< just as it can be given in a normal SVDRP connection. It doesn't
///< need to be terminated with a newline.
virtual ~cSVDRPCommand();
bool Execute(void);
///< Sends the Command given in the constructor to the remote VDR
///< and collects all of the response strings.
///< Returns true if the data exchange was successful. Whether or
///< not the actual SVDRP command was successful depends on the
///< resulting strings from the remote VDR, which can be accessed
///< by calling Response(). Execute() can be called any number of
///< times. The list of response strings will be cleared before
///< the command is actually executed.
const cStringList *Response(void) const { return &response; }
///< Returns the list of strings the remote VDR has sent in response
///< to the command. The response strings are exactly as received,
///< with the leading three digit reply code and possible continuation
///< line indicator ('-') in place.
const char *Response(int Index) { return (Index > 0 && Index < response.Size()) ? response[Index] : NULL; }
///< This is a convenience function for accessing the response strings.
///< Returns the string at the given Index, or NULL if Index is out
///< of range.
};
void SetSVDRPGrabImageDir(const char *GrabImageDir);
void StartSVDRPHandler(int Port);
void StartSVDRPHandler(int TcpPort, int UdpPort);
void StopSVDRPHandler(void);
void SendSVDRPDiscover(const char *Address = NULL);
bool GetSVDRPServerNames(cStringList *ServerNames);
///< Gets a list of all available VDRs this VDR is connected to via SVDRP,
///< and stores it in the given ServerNames list. The list is cleared
///< before getting the server names.
///< Returns true if the resulting list is not empty.
#endif //__SVDRP_H

48
tools.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: tools.c 3.4 2015/02/07 16:07:22 kls Exp $
* $Id: tools.c 4.1 2015/05/11 14:15:15 kls Exp $
*/
#include "tools.h"
@ -274,6 +274,28 @@ cString strescape(const char *s, const char *chars)
return cString(s, t != NULL);
}
cString strgetval(const char *s, const char *name, char d)
{
if (s && name) {
int l = strlen(name);
const char *t = s;
while (const char *p = strstr(t, name)) {
t = skipspace(p + l);
if (p == s || *(p - 1) <= ' ') {
if (*t == d) {
t = skipspace(t + 1);
const char *v = t;
while (*t > ' ')
t++;
return cString(v, t);
break;
}
}
}
}
return NULL;
}
bool startswith(const char *s, const char *p)
{
while (*p) {
@ -1061,6 +1083,17 @@ cString &cString::operator=(const char *String)
return *this;
}
cString &cString::Append(const char *String)
{
int l1 = strlen(s);
int l2 = strlen(String);
char *p = (char *)realloc(s, l1 + l2 + 1);
if (p != s)
strcpy(p, s);
strcpy(p + l1, String);
return *this;
}
cString &cString::Truncate(int Index)
{
int l = strlen(s);
@ -1440,6 +1473,19 @@ bool cPoller::Add(int FileHandle, bool Out)
return false;
}
void cPoller::Del(int FileHandle, bool Out)
{
if (FileHandle >= 0) {
for (int i = 0; i < numFileHandles; i++) {
if (pfd[i].fd == FileHandle && pfd[i].events == (Out ? POLLOUT : POLLIN)) {
if (i < numFileHandles - 1)
memmove(&pfd[i], &pfd[i + 1], (numFileHandles - i - 1) * sizeof(pollfd));
numFileHandles--;
}
}
}
}
bool cPoller::Poll(int TimeoutMs)
{
if (numFileHandles) {

14
tools.h
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: tools.h 3.7 2015/02/07 16:07:22 kls Exp $
* $Id: tools.h 4.1 2015/05/21 14:37:00 kls Exp $
*/
#ifndef __TOOLS_H
@ -178,6 +178,7 @@ public:
const char * operator*() const { return s; } // for use in (const void *) context (printf() etc.)
cString &operator=(const cString &String);
cString &operator=(const char *String);
cString &Append(const char *String);
cString &Truncate(int Index); ///< Truncate the string at the given Index (if Index is < 0 it is counted from the end of the string).
cString &CompactChars(char c); ///< Compact any sequence of characters 'c' to a single character, and strip all of them from the beginning and end of this string.
static cString sprintf(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
@ -209,6 +210,14 @@ char *stripspace(char *s);
char *compactspace(char *s);
char *compactchars(char *s, char c); ///< removes all occurrences of 'c' from the beginning an end of 's' and replaces sequences of multiple 'c's with a single 'c'.
cString strescape(const char *s, const char *chars);
cString strgetval(const char *s, const char *name, char d = '=');
///< Returns the value part of a 'name=value' pair in s.
///< name must either be at the beginning of s, or has to be preceded by white space.
///< There may be any number of white space around the '=' sign. The value is
///< everyting up to (and excluding) the next white space, or the end of s.
///< If an other delimiter shall be used (like, e.g., ':'), it can be given
///< as the third parameter.
///< If name occurs more than once in s, only the first occurrence is taken.
bool startswith(const char *s, const char *p);
bool endswith(const char *s, const char *p);
bool isempty(const char *s);
@ -356,12 +365,13 @@ public:
class cPoller {
private:
enum { MaxPollFiles = 16 };
enum { MaxPollFiles = 64 };
pollfd pfd[MaxPollFiles];
int numFileHandles;
public:
cPoller(int FileHandle = -1, bool Out = false);
bool Add(int FileHandle, bool Out);
void Del(int FileHandle, bool Out);
bool Poll(int TimeoutMs = 0);
};

4
vdr.c
View File

@ -22,7 +22,7 @@
*
* The project's page is at http://www.tvdr.de
*
* $Id: vdr.c 4.3 2015/04/29 09:18:54 kls Exp $
* $Id: vdr.c 4.4 2015/05/21 13:58:33 kls Exp $
*/
#include <getopt.h>
@ -916,7 +916,7 @@ int main(int argc, char *argv[])
// SVDRP:
StartSVDRPHandler(SVDRPport);
StartSVDRPHandler(SVDRPport, DEFAULTSVDRPPORT);
// Main program loop: