SASC
DVBSoftCAM

cCardClientCCcam2 Class Reference

Inheritance diagram for cCardClientCCcam2:

List of all members.

Public Member Functions

 cCardClientCCcam2 (const char *Name)
 ~cCardClientCCcam2 ()
virtual bool Init (const char *CfgDir)
virtual bool Login (void)
virtual bool CanHandle (unsigned short SysId)
virtual bool ProcessECM (const cEcmInfo *ecm, const unsigned char *data, unsigned char *Cw)
virtual bool ProcessEMM (int caSys, const unsigned char *data)
 cCardClientCCcam2 (const char *Name)
 ~cCardClientCCcam2 ()
virtual bool Init (const char *CfgDir)
virtual bool Login (void)
virtual bool CanHandle (unsigned short SysId)
virtual bool ProcessECM (const cEcmInfo *ecm, const unsigned char *data, unsigned char *Cw)
virtual bool ProcessEMM (int caSys, const unsigned char *data)

Protected Member Functions

virtual void Logout (void)
virtual void Action (void)
virtual void Logout (void)
virtual void Action (void)

Detailed Description

Definition at line 649 of file cccam2.c.


Constructor & Destructor Documentation

cCardClientCCcam2::cCardClientCCcam2 ( const char *  Name)

Definition at line 689 of file cccam2.c.

References CMD05_MODE_UNKNOWN, cNetSocket::SetRWTimeout(), and cCardClient::so.

:cCardClient(Name)
,cThread("CCcam2 reader")
{
  shareid=0; readerTid=0; pendingDCW=pendingEMM=maxecmcount=0; newcw=login=emmProcessing=false;
  cmd05mode=CMD05_MODE_UNKNOWN; cmd05off=0;
  so.SetRWTimeout(10*1000);
}
cCardClientCCcam2::~cCardClientCCcam2 ( )

Definition at line 698 of file cccam2.c.

References Logout().

{
  Logout();
}
cCardClientCCcam2::cCardClientCCcam2 ( const char *  Name)
cCardClientCCcam2::~cCardClientCCcam2 ( )

Member Function Documentation

void cCardClientCCcam2::Action ( void  ) [protected, virtual]

A derived cThread class must implement the code it wants to execute as a separate thread in this function. If this is a loop, it must check Running() repeatedly to see whether it's time to stop.

Implements cThread.

Definition at line 1270 of file cccam2.c.

References CMDLEN, cNetSocket::Connected(), cCCcamCrypt::Decrypt(), HEXDUMP, L_CC_CCCAM2, L_CC_CCCAM2DT, L_GEN_DEBUG, LDUMP, Logout(), PRINTF, cCardClient::RecvMsg(), cThread::Running(), cCardClient::so, cThread::ThreadId(), and cTimeMs::TimedOut().

{
  readerTid=cThread::ThreadId();
  int cnt=0, dec=0;
  while(Running() && so.Connected()) {
    unsigned char recvbuff[1024];
    int len=sizeof(recvbuff)-cnt;
    if(len==0) {
      HEXDUMP(L_GEN_DEBUG,recvbuff,sizeof(recvbuff),"internal: cccam2 read buffer overflow");
      Logout();
      break;
      }
    len=RecvMsg(recvbuff+cnt,-len,200);
    if(len>0) {
      PRINTF(L_CC_CCCAM2DT,"net read: len=%d cnt=%d dec=%d",len,cnt+len,dec);
      cnt+=len;
      }
    // We cannot decrypt the whole buffer because it might contain an DCW
    // cmd followed by others. But the DCW has an additional Decrypt() during
    // processing, so the crypt state would be wrong for the rest of the buffer.
    int proc=0;
    while(proc+(int)sizeof(struct CmdHeader)<=cnt) {
      // First decrypt the cmd header only!
      int a;
      if((a=proc+sizeof(struct CmdHeader)-dec)>0) {
        decr.Decrypt(recvbuff+dec,recvbuff+dec,a);
        dec+=a;
        PRINTF(L_CC_CCCAM2DT,"hdr decrypt: cnt=%d proc=%d dec=%d",cnt,proc,dec);
        }
      struct CmdHeader *hdr=(struct CmdHeader *)(recvbuff+proc);
      int l=CMDLEN(hdr);
      if(l>(int)sizeof(recvbuff)) {
        LDUMP(L_GEN_DEBUG,recvbuff+proc,sizeof(struct CmdHeader),"internal: cccam2 cmd length exceed buffer size");
        Logout();
        break;
        }
      if(proc+l>cnt) {
        PRINTF(L_CC_CCCAM2DT,"cmd incomplete: proc+l=%d cnt=%d dec=%d",proc+l,cnt,dec);
        break;
        }
      // Now decrypt payload for this cmd only!
      if((a=proc+l-dec)>0) {
        decr.Decrypt(recvbuff+dec,recvbuff+dec,a);
        dec+=a;
        PRINTF(L_CC_CCCAM2DT,"payload decrypt: cnt=%d proc=%d dec=%d",cnt,proc,dec);
        }
      LDUMP(L_CC_CCCAM2DT,hdr,l,"msg in:");
      PacketAnalyzer(hdr,l);
      proc+=l;
      }
    if(proc) {
      cnt-=proc; dec-=proc;
      memmove(recvbuff,recvbuff+proc,cnt);
      }
    if(lastsend.TimedOut()) {
      static const struct CmdHeader ping = { 0,6,0 };
      if(!CryptSend((unsigned char *)&ping,sizeof(ping)))
        PRINTF(L_CC_CCCAM2,"failed to send server PING");
      }
    usleep(10);
    }
  readerTid=0;
}
virtual void cCardClientCCcam2::Action ( void  ) [protected, virtual]

A derived cThread class must implement the code it wants to execute as a separate thread in this function. If this is a loop, it must check Running() repeatedly to see whether it's time to stop.

Implements cThread.

bool cCardClientCCcam2::CanHandle ( unsigned short  SysId) [virtual]

Reimplemented from cCardClient.

Definition at line 986 of file cccam2.c.

References cShare::CaID(), cSimpleList< T >::First(), cRwLock::Lock(), cSimpleList< T >::Next(), and cRwLock::Unlock().

Referenced by ProcessECM().

{
  if(!login) return cCardClient::CanHandle(SysId);
  bool res=false;
  shares.Lock(false);
  for(cShare *s=shares.First(); s; s=shares.Next(s))
    if(s->CaID()==SysId) { res=true; break; }
  shares.Unlock();
  return res;
}
virtual bool cCardClientCCcam2::CanHandle ( unsigned short  SysId) [virtual]

Reimplemented from cCardClient.

virtual bool cCardClientCCcam2::Init ( const char *  CfgDir) [virtual]

Implements cCardClient.

bool cCardClientCCcam2::Init ( const char *  CfgDir) [virtual]

Implements cCardClient.

Definition at line 997 of file cccam2.c.

References GetHex(), i, L_CC_CORE, LDUMP, Logout(), cCardClient::name, nodeid, cCardClient::ParseStdConfig(), PRINTF, strn0cpy(), and username.

{
  cMutexLock lock(this);
  // defaults
  strn0cpy(versstr,"2.0.11",sizeof(versstr));
  strn0cpy(buildstr,"2892",sizeof(buildstr));
  for(unsigned int i=0; i<sizeof(nodeid); i++) nodeid[i]=rand();
  wantEmus=false;

  int n=0, num=0;
  Logout();
  char params[256];
  if(!ParseStdConfig(config,&num)
     || (n=sscanf(&config[num],":%20[^:]:%63[^:]:%255[^:]",username,password,params))<2 ) return false;
  PRINTF(L_CC_CORE,"%s: username=%s password=%s",name,username,password);
  if(n>2) {
    char *save;
    char *p=strtok_r(params,",",&save);
    while(p) {
      char *v=index(p,'=');
      if(v) {
        *v++=0;
        if(!strcasecmp(p,"NODEID")) {
          const char *v2=v;
          if(GetHex(v2,nodeid,sizeof(nodeid),false)!=sizeof(nodeid)) {
            PRINTF(L_CC_CORE,"NODEID parameter format error");
            return false;
            }
          }
        else if(!strcasecmp(p,"VERSION"))
          strn0cpy(versstr,v,sizeof(versstr));
        else if(!strcasecmp(p,"BUILD"))
          strn0cpy(buildstr,v,sizeof(buildstr));
        else if(!strcasecmp(p,"WANTEMUS")) {
          wantEmus=(atoi(v)!=0);
          if(wantEmus) PRINTF(L_CC_CORE,"requesting emulations from server");
          }
        else {
          PRINTF(L_CC_CORE,"unknown parameter '%s'",p);
          return false;
          }
        }
      else {
        PRINTF(L_CC_CORE,"bad parameter format '%s'",p);
        return false;
        }
      p=strtok_r(0,",",&save);
      }
    }
  LDUMP(L_CC_CORE,nodeid,sizeof(nodeid),"our nodeid:");
  PRINTF(L_CC_CORE,"pretended CCcam version '%s' build '%s'",versstr,buildstr);
  return true;
}
virtual bool cCardClientCCcam2::Login ( void  ) [virtual]

Implements cCardClient.

bool cCardClientCCcam2::Login ( void  ) [virtual]

Implements cCardClient.

Definition at line 1070 of file cccam2.c.

References ClientInfo::build, cccamstr, cCCcamCrypt::CheckConnectChecksum(), CmdHeader::cmd, cNetSocket::Connect(), cCCcamCrypt::Decrypt(), cCCcamCrypt::Encrypt(), ClientInfo::header, cCardClient::hostname, cCCcamCrypt::Init(), L_CC_CCCAM2, L_CC_CCCAM2DT, L_CC_CCCAM2EX, L_CC_LOGIN, LDUMP, Logout(), ClientInfo::nodeid, cCardClient::port, PRINTF, cCardClient::RecvMsg(), SETCMDLEN, cNetSocket::SetQuietLog(), cCardClient::so, cThread::Start(), strn0cpy(), ClientInfo::username, username, ClientInfo::version, ClientInfo::wantemus, and cCCcamCrypt::Xor().

Referenced by ProcessECM().

{
  Logout();
  if(!so.Connect(hostname,port)) return false;
  so.SetQuietLog(true);

  unsigned char buffer[512];
  int len;
  if((len=RecvMsg(buffer,16))<0) {
    PRINTF(L_CC_CCCAM2,"no welcome from server");
    return false;
    }
  LDUMP(L_CC_CCCAM2DT,buffer,len,"welcome answer:");
  if(!cCCcamCrypt::CheckConnectChecksum(buffer,len)) {
    PRINTF(L_CC_CCCAM2,"bad welcome from server");
    Logout();
    return false;
    }
  PRINTF(L_CC_CCCAM2EX,"welcome checksum correct");

  cCCcamCrypt::Xor(buffer,len);
  unsigned char buff2[64];
  SHA1(buffer,len,buff2);
  decr.Init(buff2,20);
  decr.Decrypt(buffer,buffer,16);
  encr.Init(buffer,16);
  encr.Encrypt(buff2,buff2,20);

  LDUMP(L_CC_CCCAM2DT,buff2,20,"welcome response:");
  if(!CryptSend(buff2,20)) {
    PRINTF(L_CC_CCCAM2,"failed to send welcome response");
    return false;
    }

  memset(buffer,0,20);
  strcpy((char *)buffer,username);
  LDUMP(L_CC_CCCAM2DT,buffer,20,"send username:");
  if(!CryptSend(buffer,20)) {
    PRINTF(L_CC_CCCAM2,"failed to send username");
    return false;
    }

  encr.Encrypt((unsigned char *)password,buffer,strlen(password));
  if(!CryptSend((unsigned char *)cccamstr,6)) {
    PRINTF(L_CC_CCCAM2,"failed to send password hash");
    return false;
    }

  if((len=CryptRecv(buffer,20))<0) {
    PRINTF(L_CC_CCCAM2,"no login answer from server");
    return false;
    }
  LDUMP(L_CC_CCCAM2DT,buffer,len,"login answer:");

  if(strcmp(cccamstr,(char *)buffer)!=0) {
    PRINTF(L_CC_CCCAM2,"login failed");
    Logout();
    return false;
    }
  PRINTF(L_CC_LOGIN,"CCcam login succeed");

  struct ClientInfo clt;
  memset(&clt,0,sizeof(clt));
  clt.header.cmd=0;
  SETCMDLEN(&clt.header,sizeof(clt));
  strcpy(clt.username,username);
  strn0cpy(clt.version,versstr,sizeof(clt.version));
  strn0cpy(clt.build,buildstr,sizeof(clt.build));
  memcpy(clt.nodeid,nodeid,8);
  clt.wantemus=wantEmus;
  LDUMP(L_CC_CCCAM2DT,&clt,sizeof(clt),"send clientinfo:");
  if(!CryptSend((unsigned char*)&clt,sizeof(clt))) {
    PRINTF(L_CC_CCCAM2,"failed to send clientinfo");
    return false;
    }
  login=true;
  Start();
  return true;
}
virtual void cCardClientCCcam2::Logout ( void  ) [protected, virtual]

Reimplemented from cCardClient.

void cCardClientCCcam2::Logout ( void  ) [protected, virtual]

Reimplemented from cCardClient.

Definition at line 1051 of file cccam2.c.

References cThread::Cancel(), cSimpleListBase::Clear(), CMD05_MODE_UNKNOWN, L_CC_CCCAM2, L_CC_CCCAM2EX, cRwLock::Lock(), PRINTF, cCmd0cCrypt::Reset(), cThread::ThreadId(), and cRwLock::Unlock().

Referenced by Action(), Init(), Login(), ProcessECM(), and ~cCardClientCCcam2().

{
  PRINTF(L_CC_CCCAM2,"logout from server initiated");
  login=false;
  Cancel(cThread::ThreadId()!=readerTid ? 2:-1);
  readerTid=0;
  PRINTF(L_CC_CCCAM2EX,"reader thread stopped");
  cCardClient::Logout();
  PRINTF(L_CC_CCCAM2EX,"network shut down");
  shares.Lock(true);
  shares.Clear();
  emmProcessing=false;
  shares.Unlock();
  pendingDCW=pendingEMM=maxecmcount=0;
  cmd05mode=CMD05_MODE_UNKNOWN; cmd05off=0;
  cmd0Ccrypt.Reset();
  PRINTF(L_CC_CCCAM2EX,"logout done");
}
bool cCardClientCCcam2::ProcessECM ( const cEcmInfo *  ecm,
const unsigned char *  data,
unsigned char *  Cw 
) [virtual]

Implements cCardClient.

Definition at line 1150 of file cccam2.c.

References cEcmShares::AddStatus(), AUTOMEM, BYTE2_BE, BYTE4_BE, EcmRequest::caid, cEcmInfo::caId, CanHandle(), CheckNull(), CmdHeader::cmd, cNetSocket::Connected(), cw, EcmRequest::datalen, cEcmInfo::ecm_pid, cTimeMs::Elapsed(), cSimpleList< T >::First(), cShares::GetShares(), EcmRequest::header, cShare::Hops(), L_CC_CCCAM2, L_CC_CCCAM2DT, L_CC_CCCAM2EX, L_CC_CCCAM2SH, L_CC_ECM, cShare::Lag(), LDUMP, cMutex::Lock(), LOG, Login(), Logout(), max(), MAX_ECM_TIME, MAXLAG, cCardClient::name, cSimpleList< T >::Next(), cEcmInfo::prgId, PRINTF, EcmRequest::provid, cEcmInfo::provId, SCT_LEN, SETCMDLEN, cShares::SetLag(), EcmRequest::shareid, cShare::ShareID(), EcmRequest::sid, cCardClient::so, cShare::Status(), cTimeMs::TimedOut(), cCondVar::TimedWait(), and cMutex::Unlock().

{
  cMutexLock lock(this);
  if(!so.Connected() && !Login()) { Logout(); return false; }
  if(!CanHandle(ecm->caId)) return false;
  PRINTF(L_CC_CCCAM2,"ECM caid %04x prov %04x sid %d pid %04x",ecm->caId,ecm->provId,ecm->prgId,ecm->ecm_pid);
  int sctlen=SCT_LEN(data);
  if(sctlen>=256) {
    PRINTF(L_CC_CCCAM2,"ECM data length >=256 not supported by CCcam");
    return false;
    }
  int ecm_len=sizeof(struct EcmRequest)+sctlen;
  struct EcmRequest *req=(struct EcmRequest *)AUTOMEM(ecm_len);
  memset(req,0,sizeof(struct EcmRequest));
  memcpy(req+1,data,sctlen);
  req->header.cmd=1;
  SETCMDLEN(&req->header,ecm_len);
  BYTE2_BE(&req->caid,ecm->caId);
  BYTE4_BE(&req->provid,ecm->provId);
  BYTE2_BE(&req->sid,ecm->prgId);
  req->datalen=sctlen;
  cShares curr;
  if(curr.GetShares(ecm,&shares)<1) {
    PRINTF(L_CC_CCCAM2,"no shares for this ECM");
    return false;
    }
  if(LOG(L_CC_CCCAM2SH)) {
    PRINTF(L_CC_CCCAM2SH,"share try list for caid %04x prov %06x pid %04x",ecm->caId,ecm->provId,ecm->ecm_pid);
    for(cShare *s=curr.First(); s; s=curr.Next(s))
      PRINTF(L_CC_CCCAM2SH,"shareid %08x hops %d %c lag %4d",s->ShareID(),s->Hops(),s->Status()>0?'+':(s->Status()<0?'-':' '),s->Lag());
    }
  cTimeMs max(MAX_ECM_TIME);
  for(cShare *s=curr.First(); s && !max.TimedOut(); s=curr.Next(s)) {
    if((shareid=s->ShareID())==0) continue;
    BYTE4_BE(&req->shareid,shareid);
    PRINTF(L_CC_CCCAM2EX,"now try shareid %08x",shareid);
    LDUMP(L_CC_CCCAM2DT,req,ecm_len,"send ecm:");
    if(pendingDCW>0)
      PRINTF(L_CC_CCCAM2,"WARN: there are pending %d DCW answers. This may cause trouble...",pendingDCW);
    pendingDCW++;
    if(!CryptSend((unsigned char *)req,ecm_len)) {
      PRINTF(L_CC_CCCAM2,"failed to send ecm request");
      break;
      }
    cwmutex.Lock();
    newcw=false;
    cTimeMs lag;
    if(cwwait.TimedWait(cwmutex,MAXLAG)) {
      uint64_t l=lag.Elapsed();
      shares.SetLag(shareid,l);
      PRINTF(L_CC_CCCAM2EX,"wait returned after %lld",l);
      if(newcw) {
        // check for partial CW
        if(!CheckNull(cw+0,8)) memcpy(Cw+0,cw+0,8);
        if(!CheckNull(cw+8,8)) memcpy(Cw+8,cw+8,8);
        cwmutex.Unlock();
        ecmshares.AddStatus(ecm,shareid,1);
        PRINTF(L_CC_CCCAM2,"got CW");
        return true;
        }
      else PRINTF(L_CC_CCCAM2EX,"no CW from this share");
      }
    else {
      uint64_t l=lag.Elapsed();
      shares.SetLag(shareid,l);
      PRINTF(L_CC_CCCAM2EX,"getting CW timed out after %lld",l);
      }
    ecmshares.AddStatus(ecm,shareid,-1);
    cwmutex.Unlock();
    }
  PRINTF(L_CC_ECM,"%s: unable to decode the channel",name);
  return false;
}
virtual bool cCardClientCCcam2::ProcessECM ( const cEcmInfo *  ecm,
const unsigned char *  data,
unsigned char *  Cw 
) [virtual]

Implements cCardClient.

virtual bool cCardClientCCcam2::ProcessEMM ( int  caSys,
const unsigned char *  data 
) [virtual]

Reimplemented from cCardClient.

bool cCardClientCCcam2::ProcessEMM ( int  caSys,
const unsigned char *  data 
) [virtual]

Reimplemented from cCardClient.

Definition at line 1224 of file cccam2.c.

References cAssembleData::Assembled(), BYTE2_BE, BYTE4_BE, cMsgCache::Cache(), cShare::Cache(), EmmRequest::caid, cShare::CaID(), CmdHeader::cmd, EmmRequest::datalen, cCardClient::emmAllowed, cShare::EmmReady(), cSimpleList< T >::First(), cMsgCache::Get(), EmmRequest::header, L_CC_CCCAM2, L_CC_CCCAM2DT, LDUMP, cRwLock::Lock(), cIdSet::MatchAndAssemble(), cSimpleList< T >::Next(), PRINTF, cProvider::ProvId(), EmmRequest::provid, SCT_LEN, SETCMDLEN, cShare::ShareID(), EmmRequest::shareid, and cRwLock::Unlock().

{
  bool res=false;
  if(emmProcessing && emmAllowed) {
    cMutexLock lock(this);
    shares.Lock(false);
    for(cShare *s=shares.First(); s; s=shares.Next(s)) {
      if(s->EmmReady() && s->CaID()==caSys) {
        cProvider *p;
        cAssembleData ad(data);
        if(s->MatchAndAssemble(&ad,0,&p)) {
          const unsigned char *d;
          while((d=ad.Assembled())) {
            int len=SCT_LEN(d);
            int id=s->Cache()->Get(d,len,0);
            if(id>0 || emmAllowed>1) {
              if(len<256) {
                unsigned char bb[sizeof(struct EmmRequest)+256];
                struct EmmRequest *req=(struct EmmRequest *)bb;
                int emm_len=sizeof(struct EmmRequest)+len;
                memset(req,0,sizeof(struct EmmRequest));
                memcpy(req+1,d,len);
                req->header.cmd=2;
                SETCMDLEN(&req->header,emm_len);
                BYTE2_BE(&req->caid,s->CaID());
                BYTE4_BE(&req->provid,p ? p->ProvId() : 0);
                BYTE4_BE(&req->shareid,s->ShareID());
                req->datalen=len;
                LDUMP(L_CC_CCCAM2DT,req,emm_len,"send emm (share %08x, caid %04x, pending %d, EMM %d):",s->ShareID(),s->CaID(),pendingDCW,pendingEMM);
                pendingEMM++;
                if(!CryptSend((unsigned char *)req,emm_len))
                  PRINTF(L_CC_CCCAM2,"failed to send emm request");
                }
              else PRINTF(L_CC_CCCAM2,"EMM data length >=256 not supported by CCcam");
              s->Cache()->Cache(id,true,0);
              }
            }
          res=true;
          }
        }
      }
    shares.Unlock();
    }
  return res;
}

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