New SVDRP command MESG; SVDRP can reuse port; SVDRP timeout

This commit is contained in:
Klaus Schmidinger 2001-02-18 14:18:13 +01:00
parent c464c4f9b9
commit 3586013b8f
10 changed files with 147 additions and 17 deletions

View File

@ -350,7 +350,7 @@ Video Disk Recorder Revision History
- Encrypted channels can now be selected even without knowing the PNR (however, it
is still necessary for the EPG info).
2001-02-11: Version 0.71
2001-02-18: Version 0.71
- Fixed 'Transfer Mode' in cases where a non-primary interface was switched to
a channel that only the primary interface can receive (which could happen in
@ -392,3 +392,8 @@ Video Disk Recorder Revision History
- When removing recordings empty directories are now removed from the video
directory.
- Added the "schnitt" tools from Matthias Schniedermeyer.
- New SVDRP command MESG to display a short message on the OSD.
- The Perl script 'svdrpsend.pl' can be used to send SVDRP commands to VDR.
- SVDRP can now immediately reuse the same port if VDR is restarted.
- SVDRP now has a timeout after which the connection is automatically closed
(default is 300 seconds, can be changed in "Setup").

4
MANUAL
View File

@ -328,6 +328,10 @@ Video Disk Recorder User's Manual
to keep the EPG up-to-date.
A value of '0' turns off scanning on a single card system.
SVDRPTimeout = 300 The time (in seconds) of inactivity on an open SVDRP
connection after which the connection is automatically
closed. Default is 300, a value of 0 means no timeout.
* Executing system commands
The "Main" menu option "Commands" allows you to execute any system commands

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: config.c 1.41 2001/02/11 11:22:48 kls Exp $
* $Id: config.c 1.42 2001/02/18 13:11:59 kls Exp $
*/
#include "config.h"
@ -738,6 +738,7 @@ cSetup::cSetup(void)
MarginStart = 2;
MarginStop = 10;
EPGScanTimeout = 5;
SVDRPTimeout = 300;
CurrentChannel = -1;
}
@ -758,6 +759,7 @@ bool cSetup::Parse(char *s)
else if (!strcasecmp(Name, "MarginStart")) MarginStart = atoi(Value);
else if (!strcasecmp(Name, "MarginStop")) MarginStop = atoi(Value);
else if (!strcasecmp(Name, "EPGScanTimeout")) EPGScanTimeout = atoi(Value);
else if (!strcasecmp(Name, "SVDRPTimeout")) SVDRPTimeout = atoi(Value);
else if (!strcasecmp(Name, "CurrentChannel")) CurrentChannel = atoi(Value);
else
return false;
@ -811,6 +813,7 @@ bool cSetup::Save(const char *FileName)
fprintf(f, "MarginStart = %d\n", MarginStart);
fprintf(f, "MarginStop = %d\n", MarginStop);
fprintf(f, "EPGScanTimeout = %d\n", EPGScanTimeout);
fprintf(f, "SVDRPTimeout = %d\n", SVDRPTimeout);
fprintf(f, "CurrentChannel = %d\n", CurrentChannel);
f.Close();
isyslog(LOG_INFO, "saved setup to %s", FileName);

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: config.h 1.40 2001/02/03 15:55:45 kls Exp $
* $Id: config.h 1.41 2001/02/18 13:12:06 kls Exp $
*/
#ifndef __CONFIG_H
@ -269,6 +269,7 @@ public:
int SetSystemTime;
int MarginStart, MarginStop;
int EPGScanTimeout;
int SVDRPTimeout;
int CurrentChannel;
cSetup(void);
bool Load(const char *FileName);

7
i18n.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: i18n.c 1.12 2001/02/13 22:17:27 kls Exp $
* $Id: i18n.c 1.13 2001/02/18 13:14:00 kls Exp $
*
* Slovenian translations provided by Miha Setina <mihasetina@softhome.net>
* Italian translations provided by Alberto Carraro <bertocar@tin.it>
@ -416,6 +416,11 @@ const tPhrase Phrases[] = {
"Cas do EPG pregleda",
"Timeout EPG",
},
{ "SVDRPTimeout",
"SVDRP Timeout",
"", // TODO
"Timeout SVDRP",
},
// The days of the week:
{ "MTWTFSS",
"MDMDFSS",

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: interface.c 1.34 2001/02/02 14:49:39 kls Exp $
* $Id: interface.c 1.35 2001/02/18 10:46:13 kls Exp $
*/
#include "interface.h"
@ -70,8 +70,16 @@ unsigned int cInterface::GetCh(bool Wait, bool *Repeat, bool *Release)
eKeys cInterface::GetKey(bool Wait)
{
Flush();
if (SVDRP)
if (SVDRP) {
SVDRP->Process();
if (!open) {
char *message = SVDRP->GetMessage();
if (message) {
Info(message);
delete message;
}
}
}
eKeys Key = keyFromWait;
if (Key == kNone) {
bool Repeat = false, Release = false;
@ -281,7 +289,7 @@ void cInterface::Status(const char *s, eDvbColor FgColor, eDvbColor BgColor)
void cInterface::Info(const char *s)
{
Open();
isyslog(LOG_INFO, s);
isyslog(LOG_INFO, "info: %s", s);
Status(s, clrWhite, clrGreen);
Wait();
Status(NULL);
@ -291,7 +299,7 @@ void cInterface::Info(const char *s)
void cInterface::Error(const char *s)
{
Open();
esyslog(LOG_ERR, s);
esyslog(LOG_ERR, "ERROR: %s", s);
Status(s, clrWhite, clrRed);
Wait();
Status(NULL);

3
menu.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: menu.c 1.65 2001/02/11 11:01:47 kls Exp $
* $Id: menu.c 1.66 2001/02/18 13:12:32 kls Exp $
*/
#include "menu.h"
@ -1608,6 +1608,7 @@ void cMenuSetup::Set(void)
Add(new cMenuEditIntItem( tr("MarginStart"), &data.MarginStart));
Add(new cMenuEditIntItem( tr("MarginStop"), &data.MarginStop));
Add(new cMenuEditIntItem( tr("EPGScanTimeout"), &data.EPGScanTimeout));
Add(new cMenuEditIntItem( tr("SVDRPTimeout"), &data.SVDRPTimeout));
}
eOSState cMenuSetup::ProcessKey(eKeys Key)

54
svdrp.c
View File

@ -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 1.13 2000/12/03 15:34:35 kls Exp $
* $Id: svdrp.c 1.14 2001/02/18 14:18:13 kls Exp $
*/
#define _GNU_SOURCE
@ -63,6 +63,10 @@ bool cSocket::Open(void)
port = 0;
return false;
}
// allow it to always reuse the same port:
int ReUseAddr = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &ReUseAddr, sizeof(ReUseAddr));
//
struct sockaddr_in name;
name.sin_family = AF_INET;
name.sin_port = htons(port);
@ -137,6 +141,12 @@ const char *HelpPages[] = {
"LSTT [ <number> ]\n"
" List timers. Without option, all timers are listed. Otherwise\n"
" only the given timer is listed.",
"MESG [ <message> ]\n"
" Displays the given message on the OSD. If message is omitted, the\n"
" currently pending message (if any) will be returned. The message\n"
" will be displayed for a few seconds as soon as the OSD has become\n"
" idle. If a new MESG command is entered while the previous message\n"
" has not yet been displayed, the old message will be overwritten.",
"MODC <number> <settings>\n"
" Modify a channel. Settings must be in the same format as returned\n"
" by the LSTC command.",
@ -224,22 +234,25 @@ const char *GetHelpPage(const char *Cmd)
cSVDRP::cSVDRP(int Port)
:socket(Port)
{
message = NULL;
lastActivity = 0;
isyslog(LOG_INFO, "SVDRP listening on port %d", Port);
}
cSVDRP::~cSVDRP()
{
Close();
delete message;
}
void cSVDRP::Close(void)
void cSVDRP::Close(bool Timeout)
{
if (file.IsOpen()) {
//TODO how can we get the *full* hostname?
char buffer[MAXCMDBUFFER];
gethostname(buffer, sizeof(buffer));
Reply(221, "%s closing connection", buffer);
isyslog(LOG_INFO, "closing connection"); //TODO store IP#???
Reply(221, "%s closing connection%s", buffer, Timeout ? " (timeout)" : "");
isyslog(LOG_INFO, "closing SVDRP connection"); //TODO store IP#???
file.Close();
}
}
@ -557,6 +570,20 @@ void cSVDRP::CmdLSTT(const char *Option)
}
}
void cSVDRP::CmdMESG(const char *Option)
{
if (*Option) {
delete message;
message = strdup(Option);
isyslog(LOG_INFO, "SVDRP message: '%s'", message);
Reply(250, "Message stored");
}
else if (message)
Reply(250, "%s", message);
else
Reply(550, "No pending message");
}
void cSVDRP::CmdMODC(const char *Option)
{
if (*Option) {
@ -820,6 +847,7 @@ void cSVDRP::Execute(char *Cmd)
else if (CMD("HITK")) CmdHITK(s);
else if (CMD("LSTC")) CmdLSTC(s);
else if (CMD("LSTT")) CmdLSTT(s);
else if (CMD("MESG")) CmdMESG(s);
else if (CMD("MODC")) CmdMODC(s);
else if (CMD("MODT")) CmdMODT(s);
else if (CMD("MOVC")) CmdMOVC(s);
@ -839,7 +867,8 @@ void cSVDRP::Execute(char *Cmd)
void cSVDRP::Process(void)
{
bool SendGreeting = !file.IsOpen();
bool NewConnection = !file.IsOpen();
bool SendGreeting = NewConnection;
if (file.IsOpen() || file.Open(socket.Accept())) {
char buffer[MAXCMDBUFFER];
@ -849,6 +878,8 @@ void cSVDRP::Process(void)
time_t now = time(NULL);
Reply(220, "%s SVDRP VideoDiskRecorder %s; %s", buffer, VDRVERSION, ctime(&now));
}
if (NewConnection)
lastActivity = time(NULL);
int rbytes = file.ReadString(buffer, sizeof(buffer) - 1);
if (rbytes > 0) {
//XXX overflow check???
@ -859,11 +890,22 @@ void cSVDRP::Process(void)
buffer[rbytes] = 0;
// showtime!
Execute(buffer);
lastActivity = time(NULL);
}
else if (rbytes < 0)
Close();
else if (Setup.SVDRPTimeout && time(NULL) - lastActivity > Setup.SVDRPTimeout) {
isyslog(LOG_INFO, "timeout on SVDRP connection");
Close(true);
}
}
}
//TODO timeout???
char *cSVDRP::GetMessage(void)
{
char *s = message;
message = NULL;
return s;
}
//TODO more than one connection???

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: svdrp.h 1.6 2000/09/17 13:22:04 kls Exp $
* $Id: svdrp.h 1.7 2001/02/18 13:36:47 kls Exp $
*/
#ifndef __SVDRP_H
@ -31,7 +31,9 @@ private:
cSocket socket;
cFile file;
CRect ovlClipRects[MAXCLIPRECTS];
void Close(void);
char *message;
time_t lastActivity;
void Close(bool Timeout = false);
bool Send(const char *s, int length = -1);
void Reply(int Code, const char *fmt, ...);
void CmdCHAN(const char *Option);
@ -42,6 +44,7 @@ private:
void CmdHITK(const char *Option);
void CmdLSTC(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);
@ -59,6 +62,7 @@ public:
cSVDRP(int Port);
~cSVDRP();
void Process(void);
char *GetMessage(void);
};
#endif //__SVDRP_H

57
svdrpsend.pl Executable file
View File

@ -0,0 +1,57 @@
#!/usr/bin/perl
use Socket;
use Getopt::Std;
$Usage = qq{
Usage: $0 options command...
Options: -d hostname destination hostname (default: localhost)
-p port SVDRP port number (default: 2001)
};
die $Usage if (!$ARGV[0] || !getopts("d:p:"));
$Dest = $opt_d || "localhost";
$Port = $opt_p || 2001;
$Cmd = "@ARGV" || Error("missing command");
$Timeout = 10; # max. seconds to wait for response
$SIG{ALRM} = sub { Error("timeout"); };
alarm($Timeout);
$iaddr = inet_aton($Dest) || Error("no host: $Dest");
$paddr = sockaddr_in($Port, $iaddr);
$proto = getprotobyname('tcp');
socket(SOCK, PF_INET, SOCK_STREAM, $proto) || Error("socket: $!");
connect(SOCK, $paddr) || Error("connect: $!");
select(SOCK); $| = 1;
Receive();
Send($Cmd);
Send("quit");
close(SOCK) || Error("close: $!");
sub Send
{
my $cmd = shift || Error("no command to send");
print SOCK "$cmd\r\n";
Receive();
}
sub Receive
{
while (<SOCK>) {
print STDOUT $_;
last if substr($_, 3, 1) ne "-";
}
}
sub Error
{
print STDERR "@_\n";
close(SOCK);
exit 0;
}