SASC-NG
DVBSoftCAM

cEcmHandler Class Reference

Inheritance diagram for cEcmHandler:

List of all members.

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

Protected Member Functions

virtual void Process (cPidFilter *filter, unsigned char *data, int len)

Detailed Description

Definition at line 871 of file cam.c.


Constructor & Destructor Documentation

cEcmHandler::cEcmHandler ( cCam *  Cam,
cDevice *  Device,
const char *  DevId,
int  cwindex 
)

Definition at line 928 of file cam.c.

References bprintf().

:cAction("ecmhandler",Device,DevId)
,failed(32,0)
{
  cam=Cam;
  devId=DevId;
  cwIndex=cwindex;
  sys=0; filter=0; ecm=0; ecmPri=0; mode=-1;
  trigger=ecmUpd=false; triggerMode=-1;
  filterSource=filterTransponder=0; filterCwIndex=-1; filterSid=-1;
  id=bprintf("%s.%d",devId,cwindex);
}
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);
}

Member Function Documentation

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());
}
int cEcmHandler::CwIndex ( void  ) const [inline]

Definition at line 924 of file cam.c.

Referenced by cCam::AddPrg().

{ return cwIndex; }
const char* cEcmHandler::Id ( void  ) const [inline]

Definition at line 925 of file cam.c.

Referenced by cCam::AddPrg().

{ return id; }
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().

{
  dataMutex.Lock();
  int n=prg.pids.Count();
  dataMutex.Unlock();
  return n==0;
}
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;
      }
    }
}
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();
    }
}
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  )

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().

{
  dataMutex.Lock();
  if(!IsIdle() || prg.sid!=-1) {
    PRINTF(L_CORE_ECM,"%s: stop",id);
    prg.sid=-1;
    idleTime.Set();
    prg.pids.Clear();
    trigger=true;
    }
  dataMutex.Unlock();
  if(filter) filter->Wakeup();
}

The documentation for this class was generated from the following file:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines