|
SASC
DVBSoftCAM
|
Inheritance diagram for cEcmHandler:Public Member Functions | |
| cEcmHandler (cCam *Cam, cDevice *Device, const char *DevId, int cwindex) | |
| virtual | ~cEcmHandler () |
| void | Stop (void) |
| void | SetPrg (cPrg *Prg) |
| void | ShiftCwIndex (int cwindex) |
| char * | CurrentKeyStr (void) const |
| bool | IsRemoveable (void) |
| bool | IsIdle (void) |
| int | Sid (void) const |
| int | CwIndex (void) const |
| const char * | Id (void) const |
| cEcmHandler (cCam *Cam, cDevice *Device, const char *DevId, int cwindex) | |
| virtual | ~cEcmHandler () |
| void | Stop (void) |
| void | SetPrg (cPrg *Prg) |
| void | ShiftCwIndex (int cwindex) |
| char * | CurrentKeyStr (void) const |
| bool | IsRemoveable (void) |
| bool | IsIdle (void) |
| int | Sid (void) const |
| int | CwIndex (void) const |
| const char * | Id (void) const |
Protected Member Functions | |
| virtual void | Process (cPidFilter *filter, unsigned char *data, int len) |
| virtual void | Process (cPidFilter *filter, unsigned char *data, int len) |
| cEcmHandler::~cEcmHandler | ( | ) | [virtual] |
Definition at line 941 of file cam.c.
References cAction::DelAllFilter(), free, cThread::Lock(), and cThread::Unlock().
{
Lock();
StopEcm();
DelAllFilter(); // delete filters before sys for multi-threading reasons
DeleteSys();
Unlock();
free(id);
}
| virtual cEcmHandler::~cEcmHandler | ( | ) | [virtual] |
| char * cEcmHandler::CurrentKeyStr | ( | void | ) | const |
Definition at line 1278 of file cam.c.
References cSystem::CurrentKeyStr().
Referenced by cCam::CurrentKeyStr().
{
if(noKey || !sys) return 0;
return strdup(sys->CurrentKeyStr());
}
| char* cEcmHandler::CurrentKeyStr | ( | void | ) | const |
| int cEcmHandler::CwIndex | ( | void | ) | const [inline] |
| int cEcmHandler::CwIndex | ( | void | ) | const [inline] |
| const char* cEcmHandler::Id | ( | void | ) | const [inline] |
| const char* cEcmHandler::Id | ( | void | ) | const [inline] |
| bool cEcmHandler::IsIdle | ( | void | ) |
| bool cEcmHandler::IsIdle | ( | void | ) |
Definition at line 951 of file cam.c.
References cSimpleListBase::Count(), cMutex::Lock(), cPrg::pids, and cMutex::Unlock().
Referenced by cCam::AddPrg(), IsRemoveable(), Process(), SetPrg(), and Stop().
| bool cEcmHandler::IsRemoveable | ( | void | ) |
| bool cEcmHandler::IsRemoveable | ( | void | ) |
Definition at line 959 of file cam.c.
References cTimeMs::Elapsed(), IsIdle(), and MAX_ECM_IDLE.
{
return IsIdle() && idleTime.Elapsed()>MAX_ECM_IDLE;
}
| void cEcmHandler::Process | ( | cPidFilter * | filter, |
| unsigned char * | data, | ||
| int | len | ||
| ) | [protected, virtual] |
Implements cAction.
Definition at line 1066 of file cam.c.
References cMsgCache::Cache(), cPrg::caDescr, cEcmInfo::caId, cSystem::CheckECM(), cSystem::CheckECMResult(), cMsgCache::Clear(), cSystem::Constant(), cSystem::CW(), CW_REPEAT_TIME, cSystem::DoLog(), cCam::DumpAV7110(), ECM_DATA_TIME, cTimeMs::Elapsed(), cPidFilter::Flush(), cMsgCache::Get(), HEXDUMP, IDLE_GETCA, IDLE_GETCA_SLOW, IDLE_NO_SYNC, IDLE_SLEEP, IDLE_SYNC, IsIdle(), cCam::IsSoftCSA(), L_CORE_ECM, L_CORE_ECMPROC, L_GEN_DEBUG, L_HEX_ECM, LDUMP, cMutex::Lock(), LOG_COUNT, max(), MAX_ECM_HOLD, cSystem::MaxEcmTry(), min(), cSystem::Name(), cSystem::NeedsData(), NULL, cPidFilter::Pid(), PRINTF, cSystem::ProcessECM(), cEcmInfo::provId, cRewriter::Rewrite(), cEcmInfo::rewriter, SCT_LEN, cTimeMs::Set(), cCaDescr::Set(), cPidFilter::SetIdleTime(), cPrg::sid, cPrg::source, cTimeMs::TimedOut(), cCaDescr::ToString(), cPrg::transponder, cMutex::Unlock(), and cCam::WriteCW().
{
dataMutex.Lock();
if(trigger) {
PRINTF(L_CORE_ECM,"%s: triggered SID %d/%d idx %d/%d mode %d/%d %s",
id,filterSid,prg.sid,filterCwIndex,cwIndex,mode,triggerMode,(mode==3 && sync)?"sync":"-");
trigger=false;
if(filterSid!=prg.sid) {
filterSid=prg.sid;
filterSource=prg.source;
filterTransponder=prg.transponder;
filterCwIndex=cwIndex;
noKey=true; mode=0;
}
else {
if(filterCwIndex!=cwIndex) {
filterCwIndex=cwIndex;
if(mode==3 && sync)
cam->WriteCW(filterCwIndex,lastCw,true);
}
if(mode<triggerMode) mode=triggerMode;
}
if(!(prg.caDescr==filterCaDescr)) {
filterCaDescr.Set(&prg.caDescr);
ecmUpd=true;
//XXX
PRINTF(L_CORE_ECM,"%s: new caDescr: %s",id,*filterCaDescr.ToString());
}
triggerMode=-1;
}
dataMutex.Unlock();
switch(mode) {
case -1:
filter->SetIdleTime(IDLE_SLEEP);
break;
case 0:
StopEcm();
if(IsIdle()) { mode=-1; break; }
dolog=LOG_COUNT;
NewEcm();
filter->SetIdleTime(IDLE_GETCA);
startecm.Set();
mode=1;
break;
case 1:
if(!ecm && !JumpEcm()) {
if(startecm.Elapsed()>IDLE_GETCA_SLOW) {
if(IsIdle()) { mode=0; break; }
PRINTF(L_CORE_ECM,"%s: no encryption system found",id);
filter->SetIdleTime(IDLE_GETCA_SLOW/4);
startecm.Set();
}
break;
}
mode=4;
// fall through
case 4:
case 5:
NoSync(mode==4);
failed.Clear();
filter->SetIdleTime(IDLE_NO_SYNC/2);
lastsync.Set();
cryptPeriod=20*1000;
mode=2;
// fall through
case 2:
if(sys->NeedsData()) {
if(!UpdateEcm()) {
if(lastsync.Elapsed()<ECM_DATA_TIME) break;
PRINTF(L_CORE_ECM,"%s: no ecm extra data update (waited %d ms)",id,(int)lastsync.Elapsed());
}
if(lastsync.Elapsed()>IDLE_NO_SYNC/4 && dolog)
PRINTF(L_CORE_ECM,"%s: ecm extra data update took %d ms",id,(int)lastsync.Elapsed());
}
filter->SetIdleTime(IDLE_NO_SYNC);
mode=3;
// fall through
case 3:
{
bool resend=false, cwok=false;
if(resendTime.TimedOut()) {
resend=sync; resendTime.Set(8*24*60*60*1000);
}
if(startecm.Elapsed()<3*60*1000) cam->DumpAV7110();
if(data && len>0) {
HEXDUMP(L_HEX_ECM,data,len,"ECM sys 0x%04x id 0x%02x pid 0x%04x",ecm->caId,ecm->provId,filter->Pid());
if(SCT_LEN(data)==len) {
if(ecm->rewriter) {
ecm->rewriter->Rewrite(data,len);
HEXDUMP(L_HEX_ECM,data,len,"rewritten to");
}
LDUMP(L_CORE_ECMPROC,data,16,"%s: ECM",id);
int n;
if(!(n=sys->CheckECM(ecm,data,sync))) {
if(resend || parity!=(data[0]&1)) {
int ecmid;
cTimeMs procTime;
cwok=(ecmid=failed.Get(data,len,0))>=0 && sys->ProcessECM(ecm,data);
n=(ecmid>0)?failed.Cache(ecmid,cwok,0):99;
sys->CheckECMResult(ecm,data,cwok);
if(cwok) {
parity=data[0]&1;
}
else {
if(procTime.Elapsed()>6000) {
PRINTF(L_CORE_ECM,"%s: filter flush (elapsed %d)",id,(int)procTime.Elapsed());
filter->Flush();
}
if(n>=2) { count++; if(n==2) count++; }
parity=0xFF;
if(sync && lastsync.Elapsed()>cryptPeriod*2) {
PRINTF(L_CORE_ECM,"%s: lost sync (period %d, elapsed %d)",id,cryptPeriod,(int)lastsync.Elapsed());
NoSync(true);
}
}
PRINTF(L_CORE_ECMPROC,"%s: (%s) cwok=%d ecmid=%d n=%d sync=%d parity=%d count=%d ELA=%d",
id,sys->Name(),cwok,ecmid,n,sync,parity,count,(int)procTime.Elapsed());
}
}
else {
PRINTF(L_CORE_ECMPROC,"%s: check result %d",id,n);
switch(n) {
case 1: NoSync(true); break;
case 2: count++; break;
case 3: break;
}
}
}
else {
PRINTF(L_CORE_ECM,"%s: incomplete section %d != %d",id,len,SCT_LEN(data));
count++;
}
}
else if(sys->Constant()) {
if(sys->ProcessECM(ecm,NULL)) {
cwok=true;
if(sync) filter->SetIdleTime(IDLE_SYNC*10);
}
else count++;
}
else count++;
if(cwok) {
dolog=LOG_COUNT; sys->DoLog(true);
cam->WriteCW(filterCwIndex,sys->CW(),resend || !sync);
memcpy(lastCw,sys->CW(),sizeof(lastCw));
noKey=false; count=0;
UpdateEcm(); EcmOk();
if(!sync) {
sync=true;
filter->SetIdleTime(IDLE_SYNC);
PRINTF(L_CORE_ECM,"%s: correct key found",id);
if(!cam->IsSoftCSA(filterCwIndex==0))
resendTime.Set(CW_REPEAT_TIME);
}
else if(!resend)
cryptPeriod=max(5000,min(60000,(int)lastsync.Elapsed()));
lastsync.Set();
}
if(!sync && !trigger) {
if(count>=sys->MaxEcmTry()) {
EcmFail(); JumpEcm();
mode=4;
if(!ecm) {
JumpEcm();
if(!ecm) { // this should not happen!
PRINTF(L_GEN_DEBUG,"internal: handler %s, empty ecm list in sync loop",id);
mode=0; break;
}
// if we looped through all systems, we wait until the next parity
// change before we try again.
if(dolog!=LOG_COUNT && data) { parity=data[0]&1; mode=5; }
if(dolog && !--dolog) {
sys->DoLog(false);
PRINTF(L_CORE_ECM,"%s: stopping message log until valid key is found",id);
}
}
break;
}
}
if(IsIdle() && idleTime.Elapsed()>MAX_ECM_HOLD) {
PRINTF(L_CORE_ECM,"%s: hold timeout expired",id);
mode=0;
}
break;
}
}
}
| virtual void cEcmHandler::Process | ( | cPidFilter * | filter, |
| unsigned char * | data, | ||
| int | len | ||
| ) | [protected, virtual] |
Implements cAction.
| void cEcmHandler::SetPrg | ( | cPrg * | Prg | ) |
| void cEcmHandler::SetPrg | ( | cPrg * | Prg | ) |
Definition at line 994 of file cam.c.
References cSimpleListBase::Add(), cPrg::caDescr, cSimpleListBase::Clear(), cSimpleListBase::Del(), cSimpleList< T >::First(), cPrg::HasPidCaDescr(), IDLE_SLEEP, IsIdle(), L_CORE_ECM, L_CORE_PIDS, L_GEN_DEBUG, L_GEN_ERROR, LBEND, LBPUT, LBSTART, cMutex::Lock(), cAction::NewFilter(), cSimpleList< T >::Next(), cPrgPid::pid, pid::pid, cPrg::pids, PRINTF, cPrgPid::Proc(), cCaDescr::Set(), cTimeMs::Set(), cCam::SetCWIndex(), cPrg::sid, cPrg::source, cPrg::transponder, TYPENAME, cMutex::Unlock(), and cPidFilter::Wakeup().
Referenced by cCam::AddPrg().
{
dataMutex.Lock();
bool wasIdle=IsIdle();
if(Prg->sid!=prg.sid) {
PRINTF(L_CORE_ECM,"%s: setting new SID %d",id,Prg->sid);
prg.sid=Prg->sid;
prg.source=Prg->source;
prg.transponder=Prg->transponder;
idleTime.Set();
prg.pids.Clear();
trigger=true;
}
if(Prg->HasPidCaDescr())
PRINTF(L_GEN_DEBUG,"internal: pid specific caDescr not supported at this point (sid=%d)",Prg->sid);
LBSTART(L_CORE_PIDS);
LBPUT("%s: pids on entry",id);
for(cPrgPid *pid=prg.pids.First(); pid; pid=prg.pids.Next(pid))
LBPUT(" %s=%04x",TYPENAME(pid->type),pid->pid);
LBEND();
for(cPrgPid *pid=prg.pids.First(); pid;) {
cPrgPid *npid;
for(npid=Prg->pids.First(); npid; npid=Prg->pids.Next(npid)) {
if(pid->pid==npid->pid) {
npid->Proc(true);
break;
}
}
if(!npid) {
npid=prg.pids.Next(pid);
prg.pids.Del(pid);
pid=npid;
}
else pid=prg.pids.Next(pid);
}
LBSTART(L_CORE_PIDS);
LBPUT("%s: pids after delete",id);
for(cPrgPid *pid=prg.pids.First(); pid; pid=prg.pids.Next(pid))
LBPUT(" %s=%04x",TYPENAME(pid->type),pid->pid);
LBEND();
for(cPrgPid *npid=Prg->pids.First(); npid; npid=Prg->pids.Next(npid)) {
if(!npid->Proc()) {
cPrgPid *pid=new cPrgPid(npid->type,npid->pid);
prg.pids.Add(pid);
cam->SetCWIndex(pid->pid,cwIndex);
}
}
LBSTART(L_CORE_PIDS);
LBPUT("%s: pids after add",id);
for(cPrgPid *pid=prg.pids.First(); pid; pid=prg.pids.Next(pid))
LBPUT(" %s=%04x",TYPENAME(pid->type),pid->pid);
LBEND();
if(!IsIdle()) {
if(!(prg.caDescr==Prg->caDescr)) prg.caDescr.Set(&Prg->caDescr);
trigger=true;
triggerMode=0;
if(wasIdle) PRINTF(L_CORE_ECM,"%s: is no longer idle",id);
}
else {
if(!wasIdle) idleTime.Set();
PRINTF(L_CORE_ECM,"%s: is idle%s",id,wasIdle?"":" now");
}
if(!filter) {
filter=NewFilter(IDLE_SLEEP);
if(!filter) PRINTF(L_GEN_ERROR,"failed to open ECM filter in handler %s",id);
}
dataMutex.Unlock();
if(filter) filter->Wakeup();
}
| void cEcmHandler::ShiftCwIndex | ( | int | cwindex | ) |
Definition at line 978 of file cam.c.
References bprintf(), cSimpleList< T >::First(), free, L_CORE_PIDS, cMutex::Lock(), cSimpleList< T >::Next(), pid::pid, cPrg::pids, PRINTF, cCam::SetCWIndex(), cMutex::Unlock(), and cPidFilter::Wakeup().
{
if(cwIndex!=cwindex) {
PRINTF(L_CORE_PIDS,"%s: shifting cwIndex from %d to %d",id,cwIndex,cwindex);
free(id);
id=bprintf("%s.%d",devId,cwindex);
dataMutex.Lock();
trigger=true;
cwIndex=cwindex;
for(cPrgPid *pid=prg.pids.First(); pid; pid=prg.pids.Next(pid))
cam->SetCWIndex(pid->pid,cwIndex);
dataMutex.Unlock();
if(filter) filter->Wakeup();
}
}
| void cEcmHandler::ShiftCwIndex | ( | int | cwindex | ) |
| int cEcmHandler::Sid | ( | void | ) | const [inline] |
| int cEcmHandler::Sid | ( | void | ) | const [inline] |
Definition at line 923 of file cam.c.
References cPrg::sid.
Referenced by cCam::AddPrg().
{ return prg.sid; }
| void cEcmHandler::Stop | ( | void | ) |
| void cEcmHandler::Stop | ( | void | ) |
Definition at line 964 of file cam.c.
References cSimpleListBase::Clear(), IsIdle(), L_CORE_ECM, cMutex::Lock(), cPrg::pids, PRINTF, cTimeMs::Set(), cPrg::sid, cMutex::Unlock(), and cPidFilter::Wakeup().