./ MultiCS.r69 / ecmdata.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef WIN32
#include <windows.h>
#else
#include <fcntl.h>
#include <sys/time.h>
#include <time.h>
#include <pthread.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <errno.h>
#endif
#include "common.h"
#include "tools.h"
#include "debug.h"
#include "ecmdata.h"
ECM_DATA ecmdata[MAX_ECM_DATA];
int srvmsgid = 0;
void init_ecmdata()
{
memset(ecmdata, 0, sizeof(ecmdata));
}
uint32_t ecm_crc( uint8_t *ecm, int ecmlen)
{
uchar checksum[4];
int counter;
checksum[3]= ecm[0];
checksum[2]= ecm[1];
checksum[1]= ecm[2];
checksum[0]= ecm[3];
for ( counter=1; counter< (ecmlen/4) - 4; counter++)
{
checksum[3] ^=ecm[counter*4];
checksum[2] ^=ecm[counter*4+1];
checksum[1] ^=ecm[counter*4+2];
checksum[0] ^=ecm[counter*4+3];
}
return ( (checksum[3]<<24) | (checksum[2]<<16) | (checksum[1]<<8) | checksum[0] );
}
uint32_t hashCode( uint8_t *buf, int count)
{
int h = 0;
int i;
for (i = 0; i < count; i++) h = 31*h + buf[i];
return h;
}
ECM_DATA *getecmbyid(int id)
{
return &ecmdata[id];
}
int prevecmid( int ecmid )
{
if (ecmid<1) ecmid = MAX_ECM_DATA-1; else ecmid--;
return ecmid;
}
int nextecmid( int ecmid )
{
ecmid++; if (ecmid>=MAX_ECM_DATA) ecmid=0;
return ecmid;
}
#ifdef CHECK_NEXTDCW
void checkfreeze_storeECM(int ecmid);
#endif
uint32_t ecm_getprovid( uint8_t *ecm, uint16_t caid )
{
int32_t i, len, descriptor_length = 0;
uint32_t provid = 0;
switch(caid >> 8) {
case 0x01: // seca
provid = (ecm[3]<<8)|ecm[4];
break;
case 0x05:
// viaccess
i = (ecm[4] == 0xD2) ? ecm[5]+2 : 0; // skip d2 nano
if((ecm[5+i] == 3) && ((ecm[4+i] == 0x90) || (ecm[4+i] == 0x40)))
provid = (ecm[i+6]<<16)|(ecm[i+7]<<8)|(ecm[i+8]&0xF0);
i = (ecm[6] == 0xD2) ? ecm[7]+2 : 0; // skip d2 nano long ecm
if((ecm[7+i] == 7) && ((ecm[6+i] == 0x90) || (ecm[6+i] == 0x40)))
provid = (ecm[i+8]<<16)|(ecm[i+9]<<8)|(ecm[i+10]&0xF0);
break;
case 0x0D:
// cryptoworks
len = (((ecm[1] & 0xf) << 8) | ecm[2])+3;
for(i=8; i<len; i+=descriptor_length+2) {
descriptor_length = ecm[i+1];
if (ecm[i] == 0x83) {
provid = (uint32_t)ecm[i+2] & 0xFE;
break;
}
}
break;
}
return(provid);
}
uint16_t ecm_getchid( uint8_t *ecm, uint16_t caid )
{
if ( (caid>>8)==0x06 ) return (ecm[6]<<8)|ecm[7];
return 0;
}
int store_ecmdata(int csid, uchar *ecm,int ecmlen, unsigned short sid, unsigned short caid, unsigned int provid)
{
uint ticks = GetTickCount();
srvmsgid = nextecmid(srvmsgid);
// Check Ecm
if ( ecmdata[srvmsgid].recvtime && (ecmdata[srvmsgid].recvtime+30000>ticks) ) {
debugf(0," Cannot store ecm request\n");
return -1;
}
memset( &ecmdata[srvmsgid], 0, sizeof(ECM_DATA) );
memcpy( ecmdata[srvmsgid].ecm, ecm, ecmlen);
ecmdata[srvmsgid].csid = csid;
ecmdata[srvmsgid].chid = ecm_getchid(ecm, caid);
ecmdata[srvmsgid].ecmlen = ecmlen;
ecmdata[srvmsgid].recvtime = ticks;
ecmdata[srvmsgid].lastrecvtime = ticks;
ecmdata[srvmsgid].crc = ecm_crc(ecm, ecmlen);
ecmdata[srvmsgid].hash = hashCode(ecm+3, ecmlen-3);
ecmdata[srvmsgid].dcwstatus = STAT_DCW_WAIT;
ecmdata[srvmsgid].sid = sid;
ecmdata[srvmsgid].caid = caid;
ecmdata[srvmsgid].provid = provid;
ecmdata[srvmsgid].srvmsgid = srvmsgid;
memset( &ecmdata[srvmsgid].server, 0, sizeof(ecmdata[srvmsgid].server) );
ecmdata[srvmsgid].waitcache = 0;
ecmdata[srvmsgid].cachestatus = ECM_CACHE_NONE;
//ecmdata[srvmsgid].dcwsrvtype = DCW_SOURCE_NONE;
#ifdef CHECK_NEXTDCW
//checkfreeze_storeECM(srvmsgid);
#endif
return srvmsgid;
}
void ecm_addip( int ecmid, unsigned int ip)
{
ECM_DATA *ecm = getecmbyid(ecmid);
register int i;
for(i=0; i<20; i++) {
if (!ecm->iplist[i]) {
ecm->iplist[i] = ip;
return;
}
if (ecm->iplist[i]==ip) return;
}
}
int ecm_checkip( int ecmid, unsigned int ip)
{
ECM_DATA *ecm = getecmbyid(ecmid);
register int i;
for(i=0; i<20; i++) {
if (!ecm->iplist[i]) return FALSE;
if (ecm->iplist[i]==ip) return TRUE; // found
}
return FALSE;
}
#define TIME_ECMALIVE 60000
int search_ecmdata( uchar *ecm, int ecmlen, unsigned short sid)
{
int i;
uint32 ticks = GetTickCount();
uint32 crc = ecm_crc(ecm, ecmlen);
for (i=0; i<MAX_ECM_DATA; i++) {
if ( (ticks-ecmdata[i].recvtime) < TIME_ECMALIVE )
if (sid==ecmdata[i].sid)
if (crc==ecmdata[i].crc) return i;
}
return -1;
}
int search_ecmdata_bymsgid( int msgid )
{
int i;
uint32 ticks = GetTickCount();
for (i=0; i<MAX_ECM_DATA; i++) {
if ( (ticks-ecmdata[i].recvtime) < TIME_ECMALIVE )
if (msgid==ecmdata[i].srvmsgid) return i;
}
return -1;
}
int search_ecmdata_dcw( uchar *ecm, int ecmlen, unsigned short sid)
{
int i;
uint32 ticks = GetTickCount();
uint32 crc = ecm_crc(ecm, ecmlen);
for (i=0; i<MAX_ECM_DATA; i++) {
if ( (ticks-ecmdata[i].recvtime) < 60000 )
if (ecmdata[i].dcwstatus!=STAT_DCW_FAILED)
if (ecmlen==ecmdata[i].ecmlen)
if (crc==ecmdata[i].crc)
if (sid==ecmdata[i].sid)
if ( !memcmp(ecm, ecmdata[i].ecm, ecmlen) ) return i;
}
return -1;
}
int search_ecmdata_byhash( uint32 hash )
{
int i;
uint32 ticks = GetTickCount();
for (i=0; i<MAX_ECM_DATA; i++) {
if ( (ticks-ecmdata[i].recvtime) < TIME_ECMALIVE )
if (hash==ecmdata[i].hash) return i;
}
return -1;
}
int ecm_addsrv(ECM_DATA *ecm, unsigned int srvid)
{
int i;
uint32 ticks = GetTickCount();
for(i=0; i<20; i++) {
if (!ecm->server[i].srvid) {
ecm->server[i].srvid = srvid;
ecm->server[i].flag = ECM_SRV_REQUEST;
ecm->server[i].sendtime = ticks;
ecm->server[i].statustime = ticks; // last changed status time
return 1;
}
}
return 0;
}
int ecm_nbservers(ECM_DATA *ecm)
{
int i;
int count=0;
for(i=0; i<20; i++) {
if (ecm->server[i].srvid) {
count++;
} else break;
}
return count;
}
int ecm_nbsentsrv(ECM_DATA *ecm)
{
int i;
int count=0;
for(i=0; i<20; i++) {
if (ecm->server[i].srvid) {
if (ecm->server[i].flag!=ECM_SRV_EXCLUDE) count++;
} else break;
}
return count;
}
int ecm_nbwaitsrv(ECM_DATA *ecm)
{
int i;
int count=0;
for(i=0; i<20; i++) {
if (ecm->server[i].srvid) {
if (ecm->server[i].flag==ECM_SRV_REQUEST) count++;
} else break;
}
return count;
}
int ecm_setsrvflag(int ecmid, unsigned int srvid, int flag)
{
int i;
ECM_DATA *ecm = getecmbyid(ecmid);
for(i=0; i<20; i++) {
if (ecm->server[i].srvid) {
if (ecm->server[i].srvid==srvid) {
ecm->server[i].flag=flag;
ecm->server[i].statustime = GetTickCount();
return 1;
}
} else break;
}
return 0;
}
int ecm_setsrvflagdcw(int ecmid, unsigned int srvid, int flag, uchar dcw[16])
{
int i;
ECM_DATA *ecm = getecmbyid(ecmid);
for(i=0; i<20; i++) {
if (ecm->server[i].srvid) {
if (ecm->server[i].srvid==srvid) {
ecm->server[i].flag=flag;
ecm->server[i].statustime = GetTickCount();
memcpy(ecm->server[i].dcw, dcw, 16);
return 1;
}
} else break;
}
return 0;
}
int ecm_getsrvflag(int ecmid, unsigned int srvid)
{
int i;
ECM_DATA *ecm = getecmbyid(ecmid);
for(i=0; i<20; i++) {
if (ecm->server[i].srvid) {
if (ecm->server[i].srvid==srvid) {
return ecm->server[i].flag;
}
} else break;
}
return 0;
}
int ecm_getreplysrvid(int ecmid)
{
int i;
ECM_DATA *ecm = getecmbyid(ecmid);
for(i=0; i<20; i++)
if ( ecm->server[i].srvid && (ecm->server[i].flag==ECM_SRV_REPLY_GOOD) ) return ecm->server[i].srvid;
for(i=0; i<20; i++)
if ( ecm->server[i].srvid && (ecm->server[i].flag==ECM_SRV_REPLY_FAIL) ) return ecm->server[i].srvid;
return 0;
}
int search_ecmdata_bycw( unsigned char *cw, uint32 hash, unsigned short sid, unsigned short caid, unsigned int provid)
{
int i;
for (i=0; i<MAX_ECM_DATA; i++) {
if (ecmdata[i].dcwstatus==STAT_DCW_SUCCESS)
if (provid==ecmdata[i].provid)
if (caid==ecmdata[i].caid)
if (sid==ecmdata[i].sid)
if (hash!=ecmdata[i].hash)
if (!memcmp(cw, ecmdata[i].cw, 16)) return i;
}
return -1;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
#ifdef CHECK_NEXTDCW
/*
- search for ecm request of same channel, must be newest one and has decode success
-
*/
// Get Last DCW for the same Channel
void checkfreeze_storeECM(int ecmid)
{
// find after storing ecm
ECM_DATA *ecm = getecmbyid(ecmid);
if (!ecm) return;
if (ecm->lastdecode.status<0) return; // error
if (ecm->lastdecode.status>0) return; // already done!!!
if ( (ecm->lastdecode.status==0)&&(ecm->dcwstatus!=STAT_DCW_SUCCESS) ) {
//debugf(0," \n[SROTE ECM] New (%04x:%06x:%04x/%08x)\n",ecm->caid, ecm->provid, ecm->sid, ecm->hash);
int oldecmid = ecmid;
while ( (oldecmid=prevecmid(oldecmid)) != ecmid ) {
ECM_DATA *oldecm = getecmbyid(oldecmid);
if (!oldecm) break;
if ((ecm->recvtime-oldecm->recvtime)>60000) break;
if ( (oldecm->dcwstatus==STAT_DCW_SUCCESS)
&&(oldecm->ecmlen==ecm->ecmlen)&&(oldecm->ecm[0]!=ecm->ecm[0])
&&(oldecm->caid==ecm->caid)&&(oldecm->provid==ecm->provid)&&(oldecm->sid==ecm->sid)
) {
/*
char str1[512];
array2hex( oldecm->cw, str1, 16);
debugf(0,"Found (%04x:%06x:%04x/%08x) [%s] Stat:%d Cntr:%d Time:%d\n", oldecm->caid, oldecm->provid, oldecm->sid, oldecm->hash, str1, oldecm->lastdecode.status, oldecm->lastdecode.counter, oldecm->lastdecode.dcwchangetime);
*/
ecm->lastdecode.ecmid = oldecmid;
if ( (oldecm->lastdecode.status==1)&&(oldecm->lastdecode.counter>1) ) {
if ((ecm->recvtime-oldecm->recvtime)<(oldecm->lastdecode.dcwchangetime*12/10)) {
// found one (not sure)
ecm->lastdecode.status = 1;
ecm->lastdecode.counter = oldecm->lastdecode.counter;
// get average of ecm change time
ecm->lastdecode.dcwchangetime = (oldecm->lastdecode.dcwchangetime*oldecm->lastdecode.counter+(ecm->recvtime-oldecm->recvtime)) / (oldecm->lastdecode.counter+1);
ecm->lastdecode.dcwchangetime = ((ecm->lastdecode.dcwchangetime+300)/1000)*1000;
memcpy( ecm->lastdecode.dcw, oldecm->cw, 16); // Store latest DCW
}
}
else {
// maybe??
ecm->lastdecode.status = 1;
ecm->lastdecode.counter = oldecm->lastdecode.counter;
ecm->lastdecode.dcwchangetime = ecm->recvtime-oldecm->recvtime;
memcpy( ecm->lastdecode.dcw, oldecm->cw, 16); // Store latest DCW
}
break;
}
}
}
}
void checkfreeze_checkECM(int ecmid, int oldecmid)
{
ECM_DATA *ecm = getecmbyid(ecmid);
ECM_DATA *oldecm = getecmbyid(oldecmid);
if (!ecm) return;
if (!oldecm) return;
if ((ecm->recvtime-oldecm->recvtime)>60000) return;
if ( (oldecm->dcwstatus==STAT_DCW_SUCCESS)
&&(oldecm->ecmlen==ecm->ecmlen)&&(oldecm->ecm[0]!=ecm->ecm[0])
&&(oldecm->caid==ecm->caid)&&(oldecm->provid==ecm->provid)&&(oldecm->sid==ecm->sid)
) {
if ( (oldecm->lastdecode.status==1)&&(oldecm->lastdecode.counter>1) ) {
if ((ecm->recvtime-oldecm->recvtime)<(oldecm->lastdecode.dcwchangetime*12/10)) {
// found one (not sure)
ecm->lastdecode.status = 1;
ecm->lastdecode.counter = oldecm->lastdecode.counter;
// get average of ecm change time
ecm->lastdecode.dcwchangetime = (oldecm->lastdecode.dcwchangetime*oldecm->lastdecode.counter+(ecm->recvtime-oldecm->recvtime)) / (oldecm->lastdecode.counter+1);
ecm->lastdecode.dcwchangetime = ((ecm->lastdecode.dcwchangetime+300)/1000)*1000;
memcpy( ecm->lastdecode.dcw, oldecm->cw, 16); // Store latest DCW
}
}
else if (ecm->lastdecode.status!=1) {
// maybe??
ecm->lastdecode.status = 1;
ecm->lastdecode.counter = oldecm->lastdecode.counter;
ecm->lastdecode.dcwchangetime = ecm->recvtime-oldecm->recvtime;
memcpy( ecm->lastdecode.dcw, oldecm->cw, 16); // Store latest DCW
}
}
}
// return 0:wrong dcw, 1: good dcw
int checkfreeze_setdcw( int ecmid, uchar dcw[16] )
{
char nullcw[8] = "\0\0\0\0\0\0\0\0";
ECM_DATA *ecm = getecmbyid(ecmid);
if (!ecm) return 1;
if (ecm->lastdecode.status!=1) return 1; // no old successful decode
/*
char str1[512];
char str2[512];
array2hex( ecm->lastdecode.dcw, str1, 16);
array2hex( dcw, str2, 16);
debugf(0," \n[SET DCW] (%04x:%06x:%04x/%08x) Cntr:%d\nOLD[%s] -- NEW[%s]\n",ecm->caid, ecm->provid, ecm->sid, ecm->hash, ecm->lastdecode.counter, str1, str2);
*/
if (ecm->lastdecode.counter<2) {
// Check consecutif cw
if ( memcmp(dcw,ecm->lastdecode.dcw,16) && ( !memcmp(dcw,ecm->lastdecode.dcw,8)||!memcmp(dcw+8,ecm->lastdecode.dcw+8,8) ) )
ecm->lastdecode.counter++;
else
ecm->lastdecode.counter = 0;
//debugf(0,"OK1 New Cntr:%d\n",ecm->lastdecode.counter);
return 1;
}
else {
// Check similar cws // or null cw1/cw2 ==> no more consec.
if ( memcmp(dcw,ecm->lastdecode.dcw,16) ) { // must be not the same
if ( (!memcmp(dcw,ecm->lastdecode.dcw,8)||!memcmp(dcw+8,ecm->lastdecode.dcw+8,8)) ) {
ecm->lastdecode.counter++;
//debugf(0,"OK2 New Cntr:%d\n",ecm->lastdecode.counter);
//if (ecm->lastdecode.error) fdebugf(" ***(GOOD%d)SET DCW (%04x:%06x:%04x/%08x) Cntr:%d\nOLD[%s] -- NEW[%s]\n",ecm->lastdecode.error, ecm->caid, ecm->provid, ecm->sid, ecm->hash, ecm->lastdecode.counter, str1, str2);
return 1;
}
else if ( (!memcmp(dcw,nullcw,8)||!memcmp(dcw+8,nullcw,8)) ) {
// Remove consec
ecm->lastdecode.counter = 0;
//debugf("OK3 New Cntr:%d\n",ecm->lastdecode.counter);
return 1;
}
}
}
ecm->lastdecode.error++;
//fdebugf(" (FAILED%d) SET DCW (%04x:%06x:%04x/%08x) Cntr:%d\nOLD[%s] -- NEW[%s]\n",ecm->lastdecode.error, ecm->caid, ecm->provid, ecm->sid, ecm->hash, ecm->lastdecode.counter, str1, str2);
//debugf("FAILED\n");
return 0;
}
#endif