The channel/CAM relations are now stored in the file 'cam.data'; fixed a flaw in handling timeouts for encrypted channels

This commit is contained in:
Klaus Schmidinger 2017-01-09 13:42:41 +01:00
parent 882273d508
commit d1ddb39781
8 changed files with 114 additions and 14 deletions

View File

@ -3383,6 +3383,7 @@ Dietmar Spingler <d_spingler@gmx.de>
for suggesting to provide a way of using no DVB devices at all
for suggesting that the -V and -h options should list the plugins in alphabetical order
for suggesting to implement the setup option "Recording/Record key handling"
for suggesting to cache the channel/CAM relations in the file 'cam.data'
Stefan Schallenberg <infos@nafets.de>
for adding the functions IndexOf(), InsertUnique(), AppendUnique() and RemoveElement()

View File

@ -8882,10 +8882,16 @@ Video Disk Recorder Revision History
- Added a short sleep to cTSBuffer::Action() to avoid high CPU usage (thanks to
Sergey Chernyavskiy).
2017-01-08: Version 2.3.3
2017-01-09: Version 2.3.3
- Added 'S3W ABS-3A' to sources.conf (thanks to Frank Richter).
- Fixed a possible deadlock in the recordings handler thread.
- Updated the Russian OSD texts (thanks to Andrey Pridvorov).
- Added a missing dependency to the Makefile to avoid error messages in the
clean-plugins target (thanks to Tobias Grimm).
- The channel/CAM relations (i.e. the information which CAM can decrypt a given
channel) are now stored in the file 'cam.data' in the cache directory (suggested
by Dietmar Spingler). This speeds up switching to encrypted channels after
newly starting VDR, in case there is more than one CAM in the system.
- Fixed a flaw in handling timeouts for encrypted channels.

61
ci.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: ci.c 4.3 2016/12/23 14:00:45 kls Exp $
* $Id: ci.c 4.4 2017/01/09 12:51:05 kls Exp $
*/
#include "ci.h"
@ -13,6 +13,7 @@
#include <malloc.h>
#include <netinet/in.h>
#include <poll.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <time.h>
@ -2317,6 +2318,7 @@ void cChannelCamRelation::ClrDecrypt(int CamSlotNumber)
// --- cChannelCamRelations --------------------------------------------------
#define MAX_CAM_NUMBER 32
#define CHANNEL_CAM_RELATIONS_CLEANUP_INTERVAL 3600 // seconds between cleanups
cChannelCamRelations ChannelCamRelations;
@ -2414,3 +2416,60 @@ void cChannelCamRelations::ClrDecrypt(tChannelID ChannelID, int CamSlotNumber)
if (ccr)
ccr->ClrDecrypt(CamSlotNumber);
}
void cChannelCamRelations::Load(const char *FileName)
{
cMutexLock MutexLock(&mutex);
fileName = FileName;
if (access(fileName, R_OK) == 0) {
dsyslog("loading %s", *fileName);
if (FILE *f = fopen(fileName, "r")) {
cReadLine ReadLine;
char *s;
while ((s = ReadLine.Read(f)) != NULL) {
if (char *p = strchr(s, ' ')) {
*p = 0;
if (*++p) {
tChannelID ChannelID = tChannelID::FromString(s);
if (ChannelID.Valid()) {
char *q;
char *strtok_next;
while ((q = strtok_r(p, " ", &strtok_next)) != NULL) {
int CamSlotNumber = atoi(q);
if (CamSlotNumber >= 1 && CamSlotNumber <= MAX_CAM_NUMBER)
SetDecrypt(ChannelID, CamSlotNumber);
p = NULL;
}
}
}
}
}
fclose(f);
}
else
LOG_ERROR_STR(*fileName);
}
}
void cChannelCamRelations::Save(void)
{
cMutexLock MutexLock(&mutex);
dsyslog("saving %s", *fileName);
cSafeFile f(fileName);
if (f.Open()) {
for (cChannelCamRelation *ccr = First(); ccr; ccr = Next(ccr)) {
if (ccr->ChannelID().Valid()) {
cString s;
for (int i = 1; i <= MAX_CAM_NUMBER; i++) {
if (ccr->CamDecrypt(i))
s = cString::sprintf("%s%s%d", *s ? *s : "", *s ? " " : "", i);
}
if (*s)
fprintf(f, "%s %s\n", *ccr->ChannelID().ToString(), *s);
}
}
f.Close();
}
else
LOG_ERROR_STR(*fileName);
}

5
ci.h
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: ci.h 3.11 2015/01/31 14:36:41 kls Exp $
* $Id: ci.h 4.1 2017/01/09 12:51:05 kls Exp $
*/
#ifndef __CI_H
@ -310,6 +310,7 @@ class cChannelCamRelation;
class cChannelCamRelations : public cList<cChannelCamRelation> {
private:
cMutex mutex;
cString fileName;
cChannelCamRelation *GetEntry(tChannelID ChannelID);
cChannelCamRelation *AddEntry(tChannelID ChannelID);
time_t lastCleanup;
@ -323,6 +324,8 @@ public:
void SetDecrypt(tChannelID ChannelID, int CamSlotNumber);
void ClrChecked(tChannelID ChannelID, int CamSlotNumber);
void ClrDecrypt(tChannelID ChannelID, int CamSlotNumber);
void Load(const char *FileName);
void Save(void);
};
extern cChannelCamRelations ChannelCamRelations;

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: device.c 4.3 2016/12/23 14:43:44 kls Exp $
* $Id: device.c 4.4 2017/01/09 12:51:05 kls Exp $
*/
#include "device.h"
@ -90,6 +90,7 @@ cDevice::cDevice(void)
camSlot = NULL;
startScrambleDetection = 0;
scramblingTimeout = 0;
occupiedTimeout = 0;
@ -1574,6 +1575,7 @@ bool cDevice::Receiving(bool Dummy) const
void cDevice::Action(void)
{
time_t LastScrambledPacket = 0;
if (Running() && OpenDvr()) {
while (Running()) {
// Read data from the DVR device:
@ -1590,15 +1592,16 @@ void cDevice::Action(void)
cs = CamSlot();
CamSlotNumber = cs ? cs->SlotNumber() : 0;
if (CamSlotNumber) {
int t = time(NULL) - startScrambleDetection;
if (LastScrambledPacket < startScrambleDetection)
LastScrambledPacket = startScrambleDetection;
time_t Now = time(NULL);
if (TsIsScrambled(b)) {
if (t > TS_SCRAMBLING_TIMEOUT)
LastScrambledPacket = Now;
if (Now - startScrambleDetection > scramblingTimeout)
DetachReceivers = true;
}
else if (t > TS_SCRAMBLING_TIME_OK) {
if (Now - LastScrambledPacket > TS_SCRAMBLING_TIME_OK)
DescramblingOk = true;
startScrambleDetection = 0;
}
}
}
// Distribute the packet to all attached receivers:
@ -1606,14 +1609,17 @@ void cDevice::Action(void)
for (int i = 0; i < MAXRECEIVERS; i++) {
if (receiver[i] && receiver[i]->WantsPid(Pid)) {
if (DetachReceivers && cs && (!cs->IsActivating() || receiver[i]->Priority() >= LIVEPRIORITY)) {
dsyslog("detaching receiver - won't decrypt channel %s with CAM %d", *receiver[i]->ChannelID().ToString(), CamSlotNumber);
dsyslog("CAM %d: won't decrypt channel %s, detaching receiver", CamSlotNumber, *receiver[i]->ChannelID().ToString());
ChannelCamRelations.SetChecked(receiver[i]->ChannelID(), CamSlotNumber);
Detach(receiver[i]);
}
else
receiver[i]->Receive(b, TS_SIZE);
if (DescramblingOk)
if (DescramblingOk) {
dsyslog("CAM %d: decrypts channel %s", CamSlotNumber, *receiver[i]->ChannelID().ToString());
ChannelCamRelations.SetDecrypt(receiver[i]->ChannelID(), CamSlotNumber);
startScrambleDetection = 0;
}
}
}
Unlock();
@ -1673,6 +1679,11 @@ bool cDevice::AttachReceiver(cReceiver *Receiver)
if (camSlot && Receiver->priority > MINPRIORITY) { // priority check to avoid an infinite loop with the CAM slot's caPidReceiver
camSlot->StartDecrypting();
startScrambleDetection = time(NULL);
scramblingTimeout = TS_SCRAMBLING_TIMEOUT;
bool KnownToDecrypt = ChannelCamRelations.CamDecrypt(Receiver->ChannelID(), camSlot->SlotNumber());
if (KnownToDecrypt)
scramblingTimeout *= 10; // give it time to receive ECM/EMM
dsyslog("CAM %d: %sknown to decrypt channel %s (scramblingTimeout = %ds)", camSlot->SlotNumber(), KnownToDecrypt ? "" : "not ", *Receiver->ChannelID().ToString(), scramblingTimeout);
}
Start();
return true;

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: device.h 4.2 2016/12/06 14:12:39 kls Exp $
* $Id: device.h 4.3 2017/01/09 12:51:05 kls Exp $
*/
#ifndef __DEVICE_H
@ -425,6 +425,7 @@ public:
private:
time_t startScrambleDetection;
int scramblingTimeout;
cCamSlot *camSlot;
public:
virtual bool HasCi(void);

16
vdr.5
View File

@ -8,7 +8,7 @@
.\" License as specified in the file COPYING that comes with the
.\" vdr distribution.
.\"
.\" $Id: vdr.5 3.4 2015/02/17 13:43:53 kls Exp $
.\" $Id: vdr.5 4.1 2017/01/09 13:35:08 kls Exp $
.\"
.TH vdr 5 "19 Feb 2015" "2.2" "Video Disk Recorder Files"
.SH NAME
@ -899,6 +899,20 @@ Note that the \fBevent id\fR that comes from the DVB data stream is actually
just 16 bit wide. The internal representation in VDR allows for 32 bit to
be used, so that external tools can generate EPG data that is guaranteed
not to collide with the ids of existing data.
.SS CAM DATA
The file \fIcam.data\fR contains information about which CAM in the system can
decrypt a particular channel.
Each line in this file contains a channel id, followed by one or more (blank
separated) numbers, indicating the CAMs that have successfully decrypted this
channel earlier.
When tuning to an encrypted channel, this information is used to select the
proper CAM for decrypting this channel. This channel/CAM relationship is not
hardcoded, though. If a given channel can't be decrypted with a CAM listed
in this file, other CAMs will be tried just as well. The main purpose of this
file is to speed up channel switching in systems with more than one CAM.
This file will be read at program startup and saved when the program ends.
.SS COMMANDLINE OPTIONS
If started without any options, vdr tries to read any files in the directory
/etc/vdr/conf.d with names that do not begin with a '.' and that end with '.conf'.

7
vdr.c
View File

@ -22,7 +22,7 @@
*
* The project's page is at http://www.tvdr.de
*
* $Id: vdr.c 4.9 2016/12/23 14:34:37 kls Exp $
* $Id: vdr.c 4.10 2017/01/09 13:22:09 kls Exp $
*/
#include <getopt.h>
@ -878,6 +878,10 @@ int main(int argc, char *argv[])
if (!cPositioner::GetPositioner()) // no plugin has created a positioner
new cDiseqcPositioner;
// CAM data:
ChannelCamRelations.Load(AddDirectory(CacheDirectory, "cam.data"));
// Channel:
if (!cDevice::WaitForAllDevicesReady(DEVICEREADYTIMEOUT))
@ -1555,6 +1559,7 @@ Exit:
StopSVDRPClientHandler();
StopSVDRPServerHandler();
ChannelCamRelations.Save();
PluginManager.StopPlugins();
cRecordControls::Shutdown();
RecordingsHandler.DelAll();