|
SASC
DVBSoftCAM
|
Inheritance diagram for cCardClientCCcam2: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) |
| 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 | ( | ) |
| cCardClientCCcam2::cCardClientCCcam2 | ( | const char * | Name | ) |
| cCardClientCCcam2::~cCardClientCCcam2 | ( | ) |
| 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] |
| 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().
| 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;
}