./ MultiCS.r82 / clustredcache.c
void stringtohtml(char *src, char *dest)
{
while ( *src )
{
if ( *src=='<' ) {
*dest = '&'; dest++;
*dest = 'l'; dest++;
*dest = 't'; dest++;
*dest = ';'; dest++;
}
else if ( *src=='>' ) {
*dest = '&'; dest++;
*dest = 'g'; dest++;
*dest = 't'; dest++;
*dest = ';'; dest++;
}
else if ( *src=='&' ) {
*dest = '&'; dest++;
*dest = 'a'; dest++;
*dest = 'm'; dest++;
*dest = 'p'; dest++;
*dest = ';'; dest++;
}
else if ( *src=='"' ) {
*dest = '&'; dest++;
*dest = 'q'; dest++;
*dest = 'u'; dest++;
*dest = 'o'; dest++;
*dest = 't'; dest++;
*dest = ';'; dest++;
}
else {
*dest = *src; dest++;
}
src++;
}
*dest = 0;
}
/*
void fpeer_update(struct cacheserver_data *cache)
{
memset( cache->fpeer, 0, sizeof(cache->fpeer) ); // NULL
struct cachepeer_data *peer = cache->peer;
while (peer) {
if ( peer->host->ip ) {
int index = peer->host->ip & 0xFF;
peer->fnext = cache->fpeer[index];
cache->fpeer[index] = peer;
}
peer = peer->next;
}
}
//// Connected Peers
void ipeer_update(struct cacheserver_data *cache)
{
cache->peerReq = NULL;
cache->peerRep = NULL;
struct cachepeer_data *peer = cache->peer;
while (peer) {
if (peer->ping>0) {
if (peer->flags&FLAG_CACHE_SENDREQ) {
peer->nextreq = cache->peerReq;
cache->peerReq = peer;
}
if (peer->flags&FLAG_CACHE_SENDREP) {
peer->nextrep = cache->peerRep;
cache->peerRep = peer;
}
}
peer = peer->next;
}
}
*/
// 0: removed
int peer_doublecheck(struct cacheserver_data *cache, struct cachepeer_data *xpeer)
{
struct cachepeer_data *peer = cache->peer;
struct cachepeer_data *previous = NULL;
while (peer) {
if (peer!=xpeer)
if (peer->port==xpeer->port)
if (peer->host->ip==xpeer->host->ip) {
if (peer->runtime) {
if (previous) previous->next = peer->next; else cache->peer = peer->next;
//close(peer->outsock);
free( peer );
return 0;
}
else if (xpeer->runtime) peer_doublecheck(cache, peer);
return 1;
}
previous = peer;
peer = peer->next;
}
return 1;
}
///////////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////////
#define PEER_CSP 0x010000
#define PEER_CCCAM_CLIENT 0x020000
#define PEER_CAMD35_CLIENT 0x040000
#define PEER_CS378X_CLIENT 0x080000
#define PEER_CACHEEX_SERVER 0x100000
struct cachepeer_data *getpeerbyaddr(struct cacheserver_data *cache, uint32_t ip, uint16_t port)
{
struct cachepeer_data *peer = cache->peer;
while(peer) {
if ( (peer->host->ip==ip)&&(peer->recvport==port) ) return peer;
peer = peer->next;
}
return NULL;
}
struct cachepeer_data *getpeerbyid(int id)
{
struct cacheserver_data *cache = cfg.cache.server;
while (cache) {
struct cachepeer_data *peer = cache->peer;
while(peer) {
if (peer->id==id) return peer;
peer = peer->next;
}
cache = cache->next;
}
return NULL;
}
///////////////////////////////////////////////////////////////////////////////
// Multics ID encryption
///////////////////////////////////////////////////////////////////////////////
static unsigned char T1[]={
0x2a,0xe1,0x0b,0x13,0x3e,0x6e,0x32,0x48,
0xd3,0x31,0x08,0x8c,0x8f,0x95,0xbd,0xd0,
0xe4,0x6d,0x50,0x81,0x20,0x30,0xbb,0x75,
0xf5,0xd4,0x7c,0x87,0x2c,0x4e,0xe8,0xf4,
0xbe,0x24,0x9e,0x4d,0x80,0x37,0xd2,0x5f,
0xdb,0x04,0x7a,0x3f,0x14,0x72,0x67,0x2d,
0xcd,0x15,0xa6,0x4c,0x2e,0x3b,0x0c,0x41,
0x62,0xfa,0xee,0x83,0x1e,0xa2,0x01,0x0e,
0x7f,0x59,0xc9,0xb9,0xc4,0x9d,0x9b,0x1b,
0x9c,0xca,0xaf,0x3c,0x73,0x1a,0x65,0xb1,
0x76,0x84,0x39,0x98,0xe9,0x53,0x94,0xba,
0x1d,0x29,0xcf,0xb4,0x0d,0x05,0x7d,0xd1,
0xd7,0x0a,0xa0,0x5c,0x91,0x71,0x92,0x88,
0xab,0x93,0x11,0x8a,0xd6,0x5a,0x77,0xb5,
0xc3,0x19,0xc1,0xc7,0x8e,0xf9,0xec,0x35,
0x4b,0xcc,0xd9,0x4a,0x18,0x23,0x9f,0x52,
0xdd,0xe3,0xad,0x7b,0x47,0x97,0x60,0x10,
0x43,0xef,0x07,0xa5,0x49,0xc6,0xb3,0x55,
0x28,0x51,0x5d,0x64,0x66,0xfc,0x44,0x42,
0xbc,0x26,0x09,0x74,0x6f,0xf7,0x6b,0x4f,
0x2f,0xf0,0xea,0xb8,0xae,0xf3,0x63,0x6a,
0x56,0xb2,0x02,0xd8,0x34,0xa4,0x00,0xe6,
0x58,0xeb,0xa3,0x82,0x85,0x45,0xe0,0x89,
0x7e,0xfd,0xf2,0x3a,0x36,0x57,0xff,0x06,
0x69,0x54,0x79,0x9a,0xb6,0x6c,0xdc,0x8b,
0xa7,0x1f,0x90,0x03,0x17,0x1c,0xed,0xd5,
0xaa,0x5e,0xfe,0xda,0x78,0xb0,0xbf,0x12,
0xa8,0x22,0x21,0x3d,0xc2,0xc0,0xb7,0xa9,
0xe7,0x33,0xfb,0xf1,0x70,0xe5,0x17,0x96,
0xf8,0x8d,0x46,0xa1,0x86,0xe2,0x40,0x38,
0xf6,0x68,0x25,0x16,0xac,0x61,0x27,0xcb,
0x5b,0xc8,0x2b,0x0f,0x99,0xde,0xce,0xc5
};
static unsigned char T2[]={
0xbf,0x11,0x6d,0xfa,0x26,0x7f,0xf3,0xc8,
0x9e,0xdd,0x3f,0x16,0x97,0xbd,0x08,0x80,
0x51,0x42,0x93,0x49,0x5b,0x64,0x9b,0x25,
0xf5,0x0f,0x24,0x34,0x44,0xb8,0xee,0x2e,
0xda,0x8f,0x31,0xcc,0xc0,0x5e,0x8a,0x61,
0xa1,0x63,0xc7,0xb2,0x58,0x09,0x4d,0x46,
0x81,0x82,0x68,0x4b,0xf6,0xbc,0x9d,0x03,
0xac,0x91,0xe8,0x3d,0x94,0x37,0xa0,0xbb,
0xce,0xeb,0x98,0xd8,0x38,0x56,0xe9,0x6b,
0x28,0xfd,0x84,0xc6,0xcd,0x5f,0x6e,0xb6,
0x32,0xf7,0x0e,0xf1,0xf8,0x54,0xc1,0x53,
0xf0,0xa7,0x95,0x7b,0x19,0x21,0x23,0x7d,
0xe1,0xa9,0x75,0x3e,0xd6,0xed,0x8e,0x6f,
0xdb,0xb7,0x07,0x41,0x05,0x77,0xb4,0x2d,
0x45,0xdf,0x29,0x22,0x43,0x89,0x83,0xfc,
0xd5,0xa4,0x88,0xd1,0xf4,0x55,0x4f,0x78,
0x62,0x1e,0x1d,0xb9,0xe0,0x2f,0x01,0x13,
0x15,0xe6,0x17,0x6a,0x8d,0x0c,0x96,0x7e,
0x86,0x27,0xa6,0x0d,0xb5,0x73,0x71,0xaa,
0x36,0xd0,0x06,0x66,0xdc,0xb1,0x2a,0x5a,
0x72,0xbe,0x3a,0xc5,0x40,0x65,0x1b,0x02,
0x10,0x9f,0x3b,0xf9,0x2b,0x18,0x5c,0xd7,
0x12,0x47,0xef,0x1a,0x87,0xd2,0xc2,0x8b,
0x99,0x9c,0xd3,0x57,0xe4,0x76,0x67,0xca,
0x3c,0xfb,0x90,0x20,0x14,0x48,0xc9,0x60,
0xb0,0x70,0x4e,0xa2,0xad,0x35,0xea,0xc4,
0x74,0xcb,0x39,0xde,0xe7,0xd4,0xa3,0xa5,
0x04,0x92,0x8c,0xd9,0x7c,0x1c,0x7a,0xa8,
0x52,0x79,0xf2,0x33,0xba,0x1f,0x30,0x9a,
0x00,0x50,0x4c,0xff,0xe5,0xcf,0x59,0xc3,
0xe3,0x0a,0x85,0xb3,0xae,0xec,0x0b,0xfe,
0xe2,0xab,0x4a,0xaf,0x69,0x6c,0x2c,0x5d
};
#define SN(b) (((b&0xf0)>>4)+((b&0xf)<<4))
static void fase(unsigned char *k,unsigned char *D)
{
unsigned char l,dt; // paso 1
for(l=0;l<4;++l) D[l]^=k[l]; // paso 2
for(l=0;l<4;++l) D[l]=T1[D[l]];
for(l=6;l>3;--l) {
D[(l+2)&3]^=D[(l+1)&3];
dt=(SN(D[(l+1)&3])+D[l&3])&0xff;
D[l&3]=T2[dt];
}
for(l=3;l>0;--l) {
D[(l+2)&3]^=D[(l+1)&3];
D[l&3]=T1[(SN(D[(l+1)&3])+D[l&3])&0xff];
}
D[2]^=D[1];
D[1]^=D[0];
}
// Packet Encryption
void encryptcache(uint8_t *buf, int len)
{
int i;
for (i=1; i<len; i++) buf[i] = (buf[i]+i) & 0xff;
}
void decryptcache(uint8_t *buf, int len)
{
int i;
for (i=1; i<len; i++) buf[i] = (0xff00+buf[i]-i) & 0xff;
}
///////////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////////
#define CACHE_SENT_NONE 0
#define CACHE_SENT_REQUEST 1
#define CACHE_SENT_REPLY 2
#define BIT_CACHE_NEWPROTO 0x01
#define BIT_CACHE_HACK 0x10
#define BIT_CACHE_REQPING 0x80
// uint8_t status; // 0:Wait; 1: dcw received
#define CACHE_FLAG_DCW 0x01
// int sendpipe; // flag send dcw to ecmpipe
#define CACHE_FLAG_SENDPIPE 0x02
// Request Sent
#define CACHE_FLAG_REQSENT 0x04
// Reply Sent
#define CACHE_FLAG_REPSENT 0x08
// Forward cache to peers
#define CACHE_FLAG_FWD 0x10
// Cacheex Reply Sent
#define CACHEEX_FLAG_REPSENT 0x20
typedef enum { NO_CYCLE=0, CW0CYCLE=1, CW1CYCLE=2} cwcycle_t;
#define DCW_ERROR 0x01
#define DCW_CYCLE 0x02
#define DCW_CHECKED 0x04
#define DCW_SKIP 0x08
#define DCW_SENT 0x10
struct cw_cache_data {
struct cw_cache_data *next;
uint8_t cw[16]; // for storing all codes
uint32_t cwsum; // Checksum
uint8_t status;
cwcycle_t cwcycle; // cw1='1' / cw0='0'
uint32_t peerid; // fisrt peerid
uint16_t nbpeers; // number of peers reporting this dcw
};
struct __attribute__ ((__packed__)) cache_data {
struct cache_data *next; // main list
struct cache_data *prev; // previous
uint8_t flags;
uint32_t recvtime;
// CSP
uint8_t tag;
uint16_t sid;
uint16_t onid;
uint16_t caid;
uint32_t hash; // Non-NULL
//
uint32_t provid;
cwcycle_t cwcycle; // ecmtag when cw1 cycle
uint8_t prevcw[16];
#ifdef CACHEEX
uint8_t ecmd5[16];
#endif
struct cw_cache_data *cwdata;
ECM_DATA *ecm;
};
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
int cache_check( struct cache_data *req )
{
if ( ((req->tag&0xFE)!=0x80)||!req->caid||!req->hash||!req->sid ) return 0;
if (cfg.cache.caids[0]) {
int i;
for(i=0; i<32; i++) {
if (!cfg.cache.caids[i]) break;
if (cfg.cache.caids[i]==req->caid) return 1;
}
return 0;
}
//if (!cfg.cache.faccept0onid && !req->onid ) return 0;
return 1;
}
int cache_check_request( unsigned char tag, unsigned short sid, unsigned short onid, unsigned short caid, unsigned int hash )
{
if ( ((tag&0xFE)!=0x80)||!caid||!hash ) return 0;
//if (!cfg.cache.faccept0onid && !onid ) return 0;
return 1;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
#define MAX_CACHE_INDEX 0x3FF
////typedef struct cache_data t_cachetab[MAX_CACHE_INDEX+1];
struct cache_list {
struct cache_list *next;
//struct cache_data *cachetab[MAX_CACHE_INDEX+1];
unsigned short caid;
struct cache_data **cachetab;
};
struct cache_list *cachelist;
struct cache_data **getcachetabbycaid(unsigned short caid)
{
// look for availabe tab
struct cache_list *x = cachelist;
while (x) {
if (x->caid==caid) {
return x->cachetab;
}
x = x->next;
}
// if not found add new one
struct cache_list *newdata = malloc( sizeof(struct cache_list) );
newdata->next = cachelist;
cachelist = newdata;
newdata->caid = caid;
newdata->cachetab = malloc( sizeof(struct cache_data) * (MAX_CACHE_INDEX+1) );
memset( newdata->cachetab, 0, sizeof(struct cache_data) * (MAX_CACHE_INDEX+1) );
//printf(" New cache list for caid = %02X\n", caid);
return cachelist->cachetab;
}
struct cache_data *cache_new( struct cache_data *newdata )
{
int index = newdata->sid&MAX_CACHE_INDEX;
struct cache_data **cachetab = getcachetabbycaid(newdata->caid);
struct cache_data *pcache = cachetab[index];
struct cache_data *new;
uint32_t ticks = GetTickCount();
// add new or use dead data
if (!pcache) {
// nothing so add new
//debugf(0," first data for index = %02X\n", index);
new = malloc( sizeof(struct cache_data) );
memset( new, 0, sizeof(struct cache_data) );
new->next = NULL;
new->prev = NULL;
cachetab[index] = new; // it becomes the current one
}
else if (!pcache->next) {
//debugf(0," second data for index = %02X\n", index);
new = malloc( sizeof(struct cache_data) );
memset( new, 0, sizeof(struct cache_data) );
// add new
new->prev = cachetab[index];
new->next = cachetab[index];
// update previous
cachetab[index]->next = new;
// update next
cachetab[index]->prev = new;
//
cachetab[index] = new; // it becomes the current one
}
else {
new = cachetab[index]->prev;
if ( (new->recvtime+cfg.cache.alivetime) < ticks ) {
// cache is dead, add data to this one without allocating new data
// free old dcw
struct cw_cache_data *cwdata = new->cwdata;
while (cwdata) {
struct cw_cache_data *tmp = cwdata;
cwdata = cwdata->next;
free( tmp );
}
//debugf(0," reuse data for index = %02X\n", index);
pcache = new->prev; // store previous
memset( new, 0, sizeof(struct cache_data) );
new->prev = pcache;
new->next = cachetab[index];
cachetab[index] = new; // it becomes the current one
}
else { // allocate new data
//debugf(getdbgflag(DBG_CACHE,0,0)," new data for index = %02X\n", index);
new = malloc( sizeof(struct cache_data) );
memset( new, 0, sizeof(struct cache_data) );
// add new in list
new->prev = cachetab[index]->prev;
new->next = cachetab[index];
// update previous
cachetab[index]->prev->next = new;
// update next
cachetab[index]->prev = new;
//
cachetab[index] = new; // it becomes the current one
}
}
pcache = cachetab[index];
//pcache->status = CACHE_STAT_WAIT; // 0:Wait; 1: dcw received
pcache->recvtime = ticks;
pcache->tag = newdata->tag;
pcache->sid = newdata->sid;
pcache->onid = newdata->onid;
pcache->caid = newdata->caid;
pcache->hash = newdata->hash;
pcache->provid = newdata->provid;
#ifdef CACHEEX
memcpy( pcache->ecmd5, newdata->ecmd5, 16);
#endif
return pcache;
}
struct cache_data *cache_fetch( struct cache_data *thereq )
{
int index = thereq->sid&MAX_CACHE_INDEX;
struct cache_data **cachetab = getcachetabbycaid(thereq->caid);
struct cache_data *pcache = cachetab[index];
uint32_t ticks = GetTickCount();
while (pcache) {
if ( (pcache->recvtime+cfg.cache.alivetime) < ticks ) return NULL;
if ( (pcache->hash==thereq->hash)&&(pcache->sid==thereq->sid) )
if ( (pcache->tag==thereq->tag) || !pcache->tag || !thereq->tag ) return pcache;
pcache = pcache->next;
if (pcache==cachetab[index]) break;
}
return NULL;
}
char *cwcycle2str( cwcycle_t cwcycle )
{
if (cwcycle==CW0CYCLE) return "CW0CYCLE";
if (cwcycle==CW1CYCLE) return "CW1CYCLE";
else return "NO_CYCLE";
}
/*
int checkcycle( uint8_t cw1cycle, uint8_t ecmtag, uint8_t cwcycle )
{
if (cfg.cache.filter) {
// Check Cycle
if (cw1cycle==0x80) { // cw1 cycle on tag=0x80
if ( (ecmtag==0x80)&&(cwcycle==0) ) return 0;
if ( (ecmtag==0x81)&&(cwcycle==1) ) return 0;
}
else if (cw1cycle==0x81) { // cw1 cycle on tag=0x81
if ( (ecmtag==0x81)&&(cwcycle==0) ) return 0;
if ( (ecmtag==0x80)&&(cwcycle==1) ) return 0;
}
}
return 1;
}
*/
///////////////////////////////////////////////////////////////////////////////
// CACHE ---> ECM
///////////////////////////////////////////////////////////////////////////////
int get_cache2ecm( uint8_t *buf, struct cache_data *pcache, uint8_t *cw )
{
pcache->tag = buf[1];
pcache->sid = (buf[2]<<8) | buf[3];
pcache->onid = (buf[4]<<8) | buf[5];
pcache->caid = (buf[6]<<8) | buf[7];
pcache->hash = (buf[8]<<24) | (buf[9]<<16) | (buf[10]<<8) | (buf[11]);
// memcpy( &(pcache->tag), buf+1, 11);
int index = 12;
memcpy( &(pcache->ecm), buf+index, sizeof(void*) );
//debugf(0, " get_cache2ecm %p\n", pcache->ecm);
index += sizeof(void*);
if (cw) {
int peerid = (buf[index]<<24) | (buf[index+1]<<16) | (buf[index+2]<<8) | (buf[index+3]);
index+=4;
memcpy( cw, buf+index, 16);
return peerid;
}
return 0;
}
int put_cache2ecm(uint8_t type, uint8_t *buf, struct cache_data *pcache, uint8_t *cw, int peerid )
{
buf[0] = type;
buf[1] = pcache->tag;
buf[2] = pcache->sid>>8; buf[3] = pcache->sid&0xff;
buf[4] = pcache->onid>>8; buf[5] = pcache->onid&0xff;
buf[6] = pcache->caid>>8; buf[7] = pcache->caid&0xff;
buf[8] = pcache->hash>>24; buf[9] = pcache->hash>>16; buf[10] = pcache->hash>>8; buf[11] = pcache->hash & 0xff;
// memcpy( buf+1, &(pcache->tag), 11);
int index = 12;
memcpy( buf+index, &pcache->ecm, sizeof(void*) );
//debugf(0, " put_cache2ecm %p\n", pcache->ecm);
index += sizeof(void*);
if (cw) {
buf[index] = peerid>>24; buf[index+1] = peerid>>16; buf[index+2] = peerid>>8; buf[index+3] = peerid & 0xff;
index+=4;
memcpy( buf+index, cw, 16);
index+=16;
}
return index;
}
void pipe_cache2ecm_find_failed(struct cache_data *pcache)
{
uint8_t buf[48];
int len = put_cache2ecm(PIPE_CACHE_FIND_FAILED, buf, pcache, NULL, 0);
pipe_send( prg.pipe.ecm[1], buf, len);
}
void pipe_cache2ecm_find_success(struct cache_data *pcache, uint8_t *cw, int peerid )
{
uint8_t buf[48];
int len = put_cache2ecm(PIPE_CACHE_FIND_SUCCESS, buf, pcache, cw, peerid);
pipe_send( prg.pipe.ecm[1], buf, len);
}
///////////////////////////////////////////////////////////////////////////////
// ECM ---> CACHE
///////////////////////////////////////////////////////////////////////////////
int get_ecm2cache(uint8_t *buf , struct cache_data *pcache, uint8_t *cw)
{
pcache->tag = buf[1];
pcache->sid = (buf[2]<<8) | buf[3];
pcache->onid = (buf[4]<<8) | buf[5];
pcache->caid = (buf[6]<<8) | buf[7];
pcache->hash = (buf[8]<<24) | (buf[9]<<16) | (buf[10]<<8) | (buf[11]);
pcache->provid = (buf[12]<<16) | (buf[13]<<8) | (buf[14]);
pcache->cwcycle = buf[15];
int index = 16;
//
memcpy( &pcache->ecm, buf+index, sizeof(void*) );
index += sizeof(void*);
#ifdef CACHEEX
memcpy( pcache->ecmd5, buf+index, 16 );
index+=16;
#endif
if (cw) {
memcpy( cw, buf+index, 16 );
index+=16;
}
return index;
}
int put_ecm2cache(uint8_t type, uint8_t *buf , ECM_DATA *ecm, uint16_t onid, uint8_t *cw )
{
buf[0] = type;
buf[1] = ecm->ecm[0];
buf[2] = ecm->sid>>8; buf[3] = ecm->sid;
buf[4] = onid>>8; buf[5] = onid;
buf[6] = ecm->caid>>8; buf[7] = ecm->caid;
buf[8] = ecm->hash>>24; buf[9] = ecm->hash>>16; buf[10] = ecm->hash>>8; buf[11] = ecm->hash;
buf[12] = ecm->provid>>16; buf[13] = ecm->provid>>8; buf[14] = ecm->provid;
// cwcycle
if (!ecm->cw1cycle) buf[15] = NO_CYCLE;
else if (ecm->ecm[0]==ecm->cw1cycle) buf[15] = CW1CYCLE; else buf[15] = CW0CYCLE;
//
int index = 16;
memcpy( buf+index, &ecm, sizeof(void*) );
index += sizeof(void*);
#ifdef CACHEEX
memcpy( buf+index, ecm->ecmd5, 16 );
index+=16;
#endif
if (cw) { // previous cw if find/request, cw for reply
memcpy( buf+index, cw, 16 );
index+=16;
}
return index;
}
/*
#ifdef THREAD_DCW
void pipe_cache_find( ECM_DATA *ecm, struct cardserver_data *cs)
{
struct cache_data req;
req.tag = ecm->ecm[0];
req.sid = ecm->sid;
req.onid = cs->option.onid;
req.caid = ecm->caid;
req.hash = ecm->hash;
req.provid = ecm->provid;
req.cw1cycle = ecm->cw1cycle;
pthread_mutex_lock( &prg.lockcache );
struct cache_data *pcache = cache_fetch( &req );
if (pcache==NULL) {
pcache = cache_new( &req );
pcache->ecm = ecm;
pcache->cw1cycle = req.cw1cycle;
#ifdef CACHEEX
memcpy( pcache->ecmd5, ecm->ecmd5, 16 );
#endif
pcache->flags |= CACHE_FLAG_SENDPIPE;
// XXX set find failed
ecm->dcwstatus = STAT_DCW_WAIT;
ecm->checktime = 1;
}
else {
if (!cs->option.cachetimeout) {
ecm->dcwstatus = STAT_DCW_WAIT;
ecm->checktime = 1;
}
pcache->ecm = ecm;
pcache->tag = req.tag; // set tag if not set (coming from cahceex)
pcache->provid = req.provid; // set provid if not set (coming from csp)
pcache->cw1cycle = req.cw1cycle;
pcache->provid = req.provid;
#ifdef CACHEEX
memcpy( pcache->ecmd5, ecm->ecmd5, 16 );
#endif
pcache->flags |= CACHE_FLAG_SENDPIPE;
// Check stored cw
if (pcache->icwlist) {
int i;
for(i=0; i<pcache->icwlist; i++) {
if ( pcache->cwlist[i].status ) {
if ( checkcycle( pcache->cw1cycle, pcache->tag, pcache->cwlist[i].cwcycle ) ) {
ecm_setdcw( ecm, pcache->cwlist[i].cw, DCW_SOURCE_CACHE, pcache->cwlist[i].peerid );
}
}
}
}
}
pthread_mutex_unlock( &prg.lockcache );
}
*/
void pipe_cache_find( ECM_DATA *ecm, struct cardserver_data *cs)
{
uint8_t buf[64];
uint8_t *cw = NULL;
if ( ecm->lastdecode.ecm && (ecm->lastdecode.counter>1) ) cw = ecm->lastdecode.dcw;
int len = put_ecm2cache(PIPE_CACHE_FIND, buf, ecm, cs->option.onid, cw);
pipe_send( prg.pipe.cache[1], buf, len);
}
void pipe_cache_request( ECM_DATA *ecm, struct cardserver_data *cs)
{
uint8_t buf[64];
int len = put_ecm2cache(PIPE_CACHE_REQUEST, buf, ecm, cs->option.onid, NULL);
pipe_send( prg.pipe.cache[1], buf, len);
}
void pipe_cache_reply( ECM_DATA *ecm, struct cardserver_data *cs)
{
uint8_t buf[64];
int len;
if (ecm->dcwstatus==STAT_DCW_SUCCESS)
len = put_ecm2cache(PIPE_CACHE_REPLY, buf, ecm, cs->option.onid, ecm->cw);
else
len = put_ecm2cache(PIPE_CACHE_REPLY, buf, ecm, cs->option.onid, NULL);
pipe_send( prg.pipe.cache[1], buf, len);
}
void pipe_cache_resendreq(ECM_DATA *ecm, struct cardserver_data *cs)
{
uint8_t buf[64];
int len;
len = put_ecm2cache(PIPE_CACHE_RESENDREQ, buf, ecm, cs->option.onid, NULL);
pipe_send( prg.pipe.cache[1], buf, len);
debugf( getdbgflag(DBG_NEWCAMD,cs->id,0), " [%s] CACHE RESENDREQ ch %04x:%06x:%04x\n", cs->name,ecm->caid,ecm->provid,ecm->sid);
}
///////////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////////
void sendtoip( int handle, uint32_t ip, int port, unsigned char *buf, int len)
{
if (ip && port) {
struct sockaddr_in si_other;
int slen=sizeof(si_other);
memset((char *) &si_other, 0, sizeof(si_other));
si_other.sin_family = AF_INET;
si_other.sin_port = htons( port );
si_other.sin_addr.s_addr = ip;
sendto( handle, buf, len, 0, (struct sockaddr *)&si_other, slen );
}
}
void sendtopeer( struct cachepeer_data *peer, unsigned char *buf, int len)
{
if (peer->host->ip && peer->port) {
struct sockaddr_in si_other;
int slen=sizeof(si_other);
memset((char *) &si_other, 0, sizeof(si_other));
si_other.sin_family = AF_INET;
si_other.sin_port = htons( peer->port );
si_other.sin_addr.s_addr = peer->host->ip;
#ifdef DEBUG_NETWORK2
if (flag_debugnet) {
debugf(getdbgflag(DBG_CACHE,0,0)," cache: send data (%d) to peer (%s:%d)\n", len, peer->host->name,peer->port);
debughex(buf,len);
}
#endif
sendto(peer->outsock, buf, len, 0, (struct sockaddr *)&si_other, slen);
/*
while (1) {
struct pollfd pfd;
pfd.fd = peer->outsock;
pfd.events = POLLOUT;
int retval = poll(&pfd, 1, 10);
if (retval>0) {
if ( pfd.revents & (POLLOUT) ) {
sendto(peer->outsock, buf, len, 0, (struct sockaddr *)&si_other, slen);
} else debugf(getdbgflag(DBG_CACHE,0,0)," cache: error sending data to peer (%s:%d) \n", peer->host->name,peer->port);
break;
}
else if (retval<0) {
if ( (errno!=EINTR)&&(errno!=EAGAIN) ) {
debugf(getdbgflag(DBG_CACHE,0,0)," cache: error sending data to peer (%s:%d) \n", peer->host->name,peer->port);
break;
}
}
else debugf(getdbgflag(DBG_CACHE,0,0)," cache: error sending data to peer (%s:%d) \n", peer->host->name,peer->port);
}
*/
}
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
#define TYPE_REQUEST 1
#define TYPE_REPLY 2
#define TYPE_PINGREQ 3
#define TYPE_PINGRPL 4
#define TYPE_RESENDREQ 5
#ifdef NEWCACHE
#define TYPE_HELLO 0x03
#define TYPE_HELLO_ACK 0x10
#define TYPE_KEEPALIVE 0x11
#define TYPE_KEEPALIVE_ACK 0x12
#define TYPE_CARD_LIST 0x13
#define TYPE_SMS 0x14
#define TYPE_SMS_ACK 0x15
#define TYPE_VERSION 0x90
#define TYPE_VERSION_ACK 0x91
#define TYPE_EXTENDED 0x92
#define TYPE_EXTENDED_ACK 0x93
#define TYPE_UNKNOWN 0xFF
#endif
int peer_card_binarysearch( struct cachepeer_data *peer, uint16_t caid, uint32_t provid)
{
if (peer->nbcards==0) return 0;
int caprov = (caid<<16) | provid;
// Returns index of sid in sids, or -1 if not found
register int xl = 0;
register int xh = peer->nbcards - 1;
//
register int yl = peer->cards[xl];
register int yh = peer->cards[xh];
//
int xm;
while (yl <= caprov && yh >= caprov) {
xm = (xl + xh)/2;
int ym = peer->cards[xm];
if (ym<caprov) yl = peer->cards[xl=xm+1];
else if (ym>caprov) yh = peer->cards[xh=xm-1];
else return 1; // found
}
if (peer->cards[xl] == caprov) return 1;
return 0; // Not found
}
int peer_acceptcard( struct cachepeer_data *peer, uint16_t caid, uint32_t provid)
{
int i;
if ( peer->cards[0] ) {
int caprov = (caid<<16) | provid;
for (i=0; i<1024; i++) {
if (!peer->cards[i]) return 0;
if (peer->cards[i] == caprov) break;
}
}
if ( peer->sharelimits[0].caid!=0xffff ) {
for (i=0; i<100; i++) {
if (peer->sharelimits[i].caid==0xffff) return 0;
if (peer->sharelimits[i].caid==caid) {
if (peer->sharelimits[i].provid==provid) break;
else if (peer->sharelimits[i].provid==0xFFFFFF) break;
}
}
}
return 1;
}
void cache_send_request(struct cache_data *pcache,struct cachepeer_data *peer)
{
uint8_t buf[64];
//01 80 00CD 0001 0500 8D1DB359
buf[0] = TYPE_REQUEST;
buf[1] = pcache->tag;
buf[2] = pcache->sid>>8;
buf[3] = pcache->sid;
buf[4] = pcache->onid>>8;
buf[5] = pcache->onid&0xff;
buf[6] = pcache->caid>>8;
buf[7] = pcache->caid;
buf[8] = pcache->hash>>24;
buf[9] = pcache->hash>>16;
buf[10] = pcache->hash>>8;
buf[11] = pcache->hash;
if (peer) {
sendtopeer(peer, buf, 12);
peer->sentreq++;
}
else {
struct cacheserver_data *cache = cfg.cache.server;
while (cache) {
peer = cache->peer;
while (peer) {
if (peer->ping>0)
if (peer->flags&FLAG_CACHE_SENDREQ)
if ( !peer->fblock0onid || pcache->onid )
if ( peer_card_binarysearch(peer, pcache->caid, pcache->provid) ) {
sendtopeer(peer, buf, 12);
peer->sentreq++;
}
peer = peer->next;
}
cache = cache->next;
}
}
}
void cache_send_reply(struct cache_data *pcache,struct cachepeer_data *peer, uint8_t cw[16])
{
uint8_t buf[64];
//Common Data
buf[0] = TYPE_REPLY;
buf[1] = pcache->tag;
buf[2] = pcache->sid>>8;
buf[3] = pcache->sid;
buf[4] = pcache->onid>>8;
buf[5] = pcache->onid&0xff;
buf[6] = pcache->caid>>8;
buf[7] = pcache->caid;
buf[8] = pcache->hash>>24;
buf[9] = pcache->hash>>16;
buf[10] = pcache->hash>>8;
buf[11] = pcache->hash;
buf[12] = pcache->tag;
memcpy( buf+13, cw, 16);
if (peer) {
sendtopeer(peer, buf, 29);
//peer->sentrep++;
}
else {
struct cacheserver_data *cache = cfg.cache.server;
while (cache) {
peer = cache->peer;
while ( peer ) {
if (peer->ping>0)
//if (peer->flags&FLAG_CACHE_SENDREP)
if ( !peer->fblock0onid || pcache->onid )
if ( peer_card_binarysearch(peer, pcache->caid, pcache->provid) ) {
sendtopeer(peer, buf, 29);
peer->sentrep++;
}
peer = peer->next;
}
cache = cache->next;
}
}
}
void cache_send_fwdreply(struct cache_data *pcache, uint8_t cw[16], cwcycle_t cwcycle)
{
uint8_t buf[64];
//Common Data
buf[0] = TYPE_REPLY;
buf[1] = pcache->tag;
buf[2] = pcache->sid>>8;
buf[3] = pcache->sid;
buf[4] = pcache->onid>>8;
buf[5] = pcache->onid&0xff;
buf[6] = pcache->caid>>8;
buf[7] = pcache->caid;
buf[8] = pcache->hash>>24;
buf[9] = pcache->hash>>16;
buf[10] = pcache->hash>>8;
buf[11] = pcache->hash;
buf[12] = pcache->tag;
memcpy( buf+13, cw, 16);
buf[29] = cwcycle;
struct cacheserver_data *cache = cfg.cache.server;
while (cache) {
struct cachepeer_data *peer = cache->peer;
while ( peer ) {
//if (peer->flags&FLAG_CACHE_SENDREP)
if ( peer->ping>0 )
if ( peer->fwd )
if ( peer_card_binarysearch(peer, pcache->caid, pcache->provid) ) {
sendtopeer(peer, buf, 30);
peer->sentrep++;
}
peer = peer->next;
}
cache = cache->next;
}
}
void cache_send_resendreq(struct cache_data *pcache)
{
struct cacheserver_data *cache = cfg.cache.server;
while (cache) {
// <1:TYPE_RESENDREQ> <2:port> <1:ecmtag> <2:sid> <2:onid> <2:caid> <4:hash>
uint8_t buf[64];
buf[0] = TYPE_RESENDREQ;
//Port
buf[1] = 0;
buf[2] = 0;
buf[3] = cache->port>>8;
buf[4] = cache->port&0xff;
buf[5] = pcache->tag;
buf[6] = pcache->sid>>8;
buf[7] = pcache->sid;
buf[8] = pcache->onid>>8;
buf[9] = pcache->onid&0xff;
buf[10] = pcache->caid>>8;
buf[11] = pcache->caid;
buf[12] = pcache->hash>>24;
buf[13] = pcache->hash>>16;
buf[14] = pcache->hash>>8;
buf[15] = pcache->hash;
struct cachepeer_data *peer = cache->peer;
while ( peer ) {
if ( peer->ping>0 )
if ( peer_card_binarysearch(peer, pcache->caid, pcache->provid) )
sendtopeer(peer, buf, 16);
peer = peer->next;
}
cache = cache->next;
}
}
void cache_send_ping(struct cacheserver_data *cache, struct cachepeer_data *peer)
{
unsigned char buf[32];
buf[0] = TYPE_PINGREQ;
// New Cache IDENT
buf[1] = 'M';
buf[2] = 'C';
/// buf[3] = 1 | BIT_CACHE_HACK;
buf[3] = 1;
// PEER ID
buf[4] = peer->id>>8;
buf[5] = peer->id&0xff;
// MULTICS CRC
buf[6] = peer->crc[0] = 0xff & rand();
buf[7] = peer->crc[1] = 0xff & rand();
buf[8] = peer->crc[2] = 0xff & rand();
//Port
buf[9] = peer->crc[3] = 0;
buf[10] = 0;
buf[11] = cache->port>>8;
buf[12] = cache->port&0xff;
//Program
buf[13] = 0x01; //ID
buf[14] = 7; //LEN
buf[15] = 'M'; buf[16] = 'u'; buf[17] = 'l'; buf[18] = 't'; buf[19] = 'i'; buf[20] = 'C'; buf[21] = 'S';
//Version
buf[22] = 0x02; //ID
buf[23] = 3; //LEN
buf[24] = 'r'; buf[25] = '0'+(REVISION/10); buf[26] = '0'+(REVISION%10);
//
sendtopeer( peer, buf, 27);
}
#ifdef NEWCACHE
void cache_send_keepalive(struct cacheserver_data *cache, struct cachepeer_data *peer)
{
if (peer->protocol&1) {
unsigned char buf[32];
buf[0] = TYPE_KEEPALIVE;
buf[1] = peer->id>>8;
buf[2] = peer->id&0xff;
sendtopeer( peer, buf, 3);
}
else cache_send_ping(cache, peer);
}
void save_sms( struct sms_data *sms, struct cachepeer_data *peer)
{
// print to sms file
FILE *fhandle;
fhandle=fopen(sms_file, "at");
if (fhandle!=0) {
// Get Time
char timebuf [80];
struct tm * timeinfo = localtime (&sms->rawtime);
strftime (timebuf,80,"%x %X",timeinfo);
if (sms->status&1) fprintf(fhandle,"\n\n[ %s ] >> SMS to peer (%s:%d)\n", timebuf, peer->host->name, peer->port);
else fprintf(fhandle,"\n\n[ %s ] << SMS from peer (%s:%d)\n", timebuf, peer->host->name, peer->port);
fputs(sms->msg, fhandle);
fclose(fhandle);
}
}
struct sms_data *cache_new_sms(char *msg)
{
struct sms_data *sms = malloc( sizeof(struct sms_data) );
int len = strlen(msg);
uint32_t hash = hashCode((uint8_t*)msg, len);
strcpy( sms->msg, msg );
sms->hash = hash;
time (&sms->rawtime);
sms->next = NULL;
return (sms);
}
void cache_send_sms(struct cachepeer_data *peer, struct sms_data *sms)
{
int len = strlen(sms->msg);
sms->status = 1; // bit 0 (0:in,1:out) bit 1 (0:unread/unack, 1:read/ack)
sms->next = peer->sms;
peer->sms = sms;
// Send Buffer
uint8_t buf[1024];
buf[0] = TYPE_SMS;
buf[1] = sms->hash>>24;
buf[2] = sms->hash>>16;
buf[3] = sms->hash>>8;
buf[4] = sms->hash;
memcpy( buf+5, sms->msg, len );
sendtopeer(peer, buf, len+5);
// Debug
debugf(getdbgflag(DBG_CACHE,0,0)," SMS to peer (%s:%d)\n", peer->host->name, peer->port);
save_sms( sms, peer);
}
#endif
void peer_check_messages( struct cachepeer_data *peer )
{
// Remove Old Messages if there is too much
struct sms_data *sms = peer->sms;
int nb = 0;
while (sms) {
nb++;
if (nb>=30) break;
sms = sms->next;
}
// Remove Messages
if (sms) {
struct sms_data *next = sms->next;
sms->next = NULL;
while (next) {
sms = next;
next = sms->next;
free(sms);
}
}
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// DCW CHECK & SET
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
/*
look for older cw anf check for cwcycle
return
-1 : error
0: nothing found
1: found cycle
*/
int cache_fetch_goodcw( struct cache_data *thereq, uint8_t cw[16], cwcycle_t *cwcycle )
{
#ifdef TESTCHANNEL
int testchannel = ( (thereq->caid==cfg.testchn.caid) && (!thereq->provid || thereq->provid==cfg.testchn.provid) && (thereq->sid==cfg.testchn.sid) );
if (testchannel) {
char dump[64];
array2hex( cw, dump, 16);
char dump2[64];
array2hex( thereq->prevcw, dump2, 16);
fdebugf(" (cache_fetch_goodcw.%x) ch %04x:%06x:%04x/%02x:%08x -> %s (%s) P:%s\n", thereq->flags&CACHE_FLAG_SENDPIPE, thereq->caid, thereq->provid, thereq->sid,
thereq->tag, thereq->hash, dump, cwcycle2str(thereq->cwcycle), dump2 );
}
#endif
int index = thereq->sid&MAX_CACHE_INDEX;
struct cache_data **cachetab = getcachetabbycaid(thereq->caid);
struct cache_data *pcache = cachetab[index];
struct cache_data *result = NULL;
uint32_t ticks = GetTickCount() - cfg.cache.alivetime;
while (pcache) {
if ( (pcache->recvtime+cfg.cache.filtertime)<thereq->recvtime) {
if ( pcache->recvtime < ticks ) break;
if ( (pcache->sid==thereq->sid)&&(pcache->hash!=thereq->hash) ) // need provider XXX
if ( !pcache->provid || !thereq->provid || (pcache->provid==thereq->provid) ) // csp luck of provid
if ( pcache->tag && (pcache->tag!=thereq->tag) ) { // old oscam cacheex luck of ecmtag
struct cw_cache_data *cwdata = pcache->cwdata;
while (cwdata) {
if ( dcwcmp16(cwdata->cw,cw) ) {
#ifdef TESTCHANNEL
if (testchannel) {
char dump[64];
array2hex( cwdata->cw, dump, 16);
fdebugf(" >> Same dcw, cache %04x:%06x:%04x/%02x:%08x::%s\n", pcache->caid, pcache->provid, pcache->sid, pcache->tag, pcache->hash, dump);
}
#endif
return DCW_ERROR; // not gooooooooooooood maybe another provider of same channel
}
else if ( !(cwdata->status&DCW_ERROR) ) {
if ( dcwcmp8(cwdata->cw,cw) && !similarcw(cwdata->cw+8,cw+8) ) { // ????????????????????????????
if (cwdata->cwcycle!=CW1CYCLE) {
*cwcycle = CW1CYCLE; // CW1 changed
#ifdef TESTCHANNEL
if (testchannel) {
char dump[64];
array2hex( cwdata->cw, dump, 16);
fdebugf(" >> CW1 cycle(%d) cache %04x:%06x:%04x/%02x:%08x::%s\n", cwdata->status, pcache->caid, pcache->provid, pcache->sid, pcache->tag, pcache->hash, dump);
}
#endif
if (cwdata->status&DCW_CYCLE) return DCW_CYCLE;
result = pcache;
}
}
else if ( !similarcw(cwdata->cw,cw) && dcwcmp8(cwdata->cw+8,cw+8) ) {
if (cwdata->cwcycle!=CW0CYCLE) {
*cwcycle = CW0CYCLE; // CW0 changed
#ifdef TESTCHANNEL
if (testchannel) {
char dump[64];
array2hex( cwdata->cw, dump, 16);
fdebugf(" >> CW0 cycle(%d) cache %04x:%06x:%04x/%02x:%08x::%s\n", cwdata->status, pcache->caid, pcache->provid, pcache->sid, pcache->tag, pcache->hash, dump);
}
#endif
if (cwdata->status&DCW_CYCLE) return DCW_CYCLE; //2
result = pcache;
}
}
}
cwdata = cwdata->next;
}
}
}
pcache = pcache->next;
if (pcache==cachetab[index]) break;
}
if (result) return DCW_CYCLE; //1
return 0; //DCW_NOCYCLE
}
// search for same cw in cache
int cache_check_cw( uint32_t recvtime, uint8_t tag, uint16_t caid, uint32_t hash, uint16_t sid, uint8_t cw[16], int cwpart )
{
int index = sid&MAX_CACHE_INDEX;
struct cache_data **cachetab = getcachetabbycaid(caid);
struct cache_data *pcache = cachetab[index];
uint32_t ticks = GetTickCount() - cfg.cache.alivetime;
while (pcache) {
if ( (pcache->recvtime+cfg.cache.filtertime)<recvtime) {
if ( pcache->recvtime < ticks ) break;
if ( (pcache->sid==sid)&&(pcache->hash!=hash)&&(pcache->tag!=tag) ) { // ??? maybe find same dcw for different providers
struct cw_cache_data *cwdata = pcache->cwdata;
while (cwdata) {
switch (cwpart) {
case 0:
if ( dcwcmp8(cwdata->cw,cw) ) return 0;
if ( dcwcmp8(cwdata->cw+8,cw) ) return 0;
break;
case 1:
if ( dcwcmp8(cwdata->cw,cw+8) ) return 0;
if ( dcwcmp8(cwdata->cw+8,cw+8) ) return 0;
break;
case 2:
if ( dcwcmp16(cwdata->cw,cw) ) return 0;
break;
}
cwdata = cwdata->next;
}
}
}
pcache = pcache->next;
if (pcache==cachetab[index]) break;
}
return 1;
}
struct cw_cache_data *iscwincache(struct cache_data *pcache, uint8_t cw[16])
{
struct cw_cache_data *cwdata = pcache->cwdata;
while (cwdata) {
if ( dcwcmp16(cwdata->cw, cw) ) return cwdata;
cwdata = cwdata->next;
}
return NULL;
}
// update dcw for cache data of same channel with different hash and provider
struct cache_data *cache_fetch_goodcw2( struct cache_data *thereq, uint8_t cw[16], int peerid )
{
#ifdef TESTCHANNEL
int testchannel = ( (thereq->caid==cfg.testchn.caid) && (!thereq->provid || thereq->provid==cfg.testchn.provid) && (thereq->sid==cfg.testchn.sid) );
if (testchannel) {
char dump[64];
array2hex( cw, dump, 16);
fdebugf(" (cache_fetch_goodcw2) ch %04x:%06x:%04x/%02x:%08x -> %s\n", thereq->caid, thereq->provid, thereq->sid, thereq->tag, thereq->hash, dump);
}
#endif
int index = thereq->sid&MAX_CACHE_INDEX;
struct cache_data **cachetab = getcachetabbycaid(thereq->caid);
struct cache_data *pcache = cachetab[index];
struct cache_data *result = NULL;
uint32_t ticks = GetTickCount() - cfg.cache.alivetime;
while (pcache) {
if ( pcache->recvtime < ticks ) break;
if ( pcache->flags&CACHE_FLAG_SENDPIPE )
if ( (pcache->sid==thereq->sid)&&(pcache->hash!=thereq->hash) ) // need provider XXX
//if ( !pcache->provid || !thereq->provid || (pcache->provid!=thereq->provid) )
if ( pcache->tag && (pcache->tag==thereq->tag) )
if ( pcache->cwcycle!=NO_CYCLE )
if ( !isnullDCW(pcache->prevcw) )
if ( !iscwincache(pcache,cw) )
{
if ( ( (pcache->cwcycle==CW1CYCLE) && dcwcmp8(pcache->prevcw,cw) && !similarcw(pcache->prevcw+8,cw+8) ) ||
( (pcache->cwcycle==CW0CYCLE) && !similarcw(pcache->prevcw,cw) && dcwcmp8(pcache->prevcw+8,cw+8) ) ) {
pipe_cache2ecm_find_success(pcache, cw, peerid);
#ifdef TESTCHANNEL
if (testchannel) {
char dump1[64];
char dump2[64];
array2hex( cw, dump1, 16);
array2hex( pcache->prevcw, dump2, 16);
fdebugf(" ==%s== cache %04x:%06x:%04x/%02x:%08x %s => %s\n", cwcycle2str(pcache->cwcycle), pcache->caid, pcache->provid, pcache->sid, pcache->tag, pcache->hash, dump2,dump1);
fdebugf(" ==%s== Update %04x:%06x:%04x/%02x:%08x from %04x:%06x:%04x/%02x:%08x\n", cwcycle2str(pcache->cwcycle),
pcache->caid, pcache->provid, pcache->sid, pcache->tag, pcache->hash,
thereq->caid, thereq->provid, thereq->sid, thereq->tag, thereq->hash );
}
#endif
}
}
pcache = pcache->next;
if (pcache==cachetab[index]) break;
}
return result;
}
// cache check3
// update dcw for cache data of same caid,tag,hash with different sid
//[17:36:34.278] <- ecm from cs378x client 'm1' ch 0100:003315:233d:41353b6b
//[17:36:34.278] <- ecm from cs378x client 'm1' ch 0100:003315:2351:41353b6b
struct cache_data *cache_fetch_goodcw3( struct cache_data *thereq, uint8_t cw[16], int peerid )
{
#ifdef TESTCHANNEL
int testchannel = ( (thereq->caid==cfg.testchn.caid) && (!thereq->provid || thereq->provid==cfg.testchn.provid) && (thereq->sid==cfg.testchn.sid) );
if (testchannel) {
char dump[64];
array2hex( cw, dump, 16);
fdebugf(" (cache_fetch_goodcw3) ch %04x:%06x:%04x/%02x:%08x -> %s\n", thereq->caid, thereq->provid, thereq->sid, thereq->tag, thereq->hash, dump);
}
#endif
int index = thereq->sid&MAX_CACHE_INDEX;
struct cache_data **cachetab = getcachetabbycaid(thereq->caid);
struct cache_data *pcache = cachetab[index];
struct cache_data *result = NULL;
uint32_t ticks = GetTickCount() - cfg.cache.alivetime;
while (pcache) {
if ( pcache->recvtime < ticks ) break;
if ( pcache->flags&CACHE_FLAG_SENDPIPE )
if (pcache->sid!=thereq->sid)
if ( (pcache->hash==thereq->hash) ) // need provider XXX
if ( pcache->tag && (pcache->tag==thereq->tag) )
if ( pcache->cwcycle!=NO_CYCLE )
if ( !isnullDCW(pcache->prevcw) )
if ( !iscwincache(pcache,cw) )
{
if ( ( (pcache->cwcycle==CW1CYCLE) && dcwcmp8(pcache->prevcw,cw) && !similarcw(pcache->prevcw+8,cw+8) ) ||
( (pcache->cwcycle==CW0CYCLE) && !similarcw(pcache->prevcw,cw) && dcwcmp8(pcache->prevcw+8,cw+8) ) ) {
pipe_cache2ecm_find_success(pcache, cw, peerid);
#ifdef TESTCHANNEL
if (testchannel) {
char dump1[64];
char dump2[64];
array2hex( cw, dump1, 16);
array2hex( pcache->prevcw, dump2, 16);
fdebugf(" ==%s== cache %04x:%06x:%04x/%02x:%08x %s => %s\n", cwcycle2str(pcache->cwcycle), pcache->caid, pcache->provid, pcache->sid, pcache->tag, pcache->hash, dump2,dump1);
fdebugf(" ==%s== Update %04x:%06x:%04x/%02x:%08x from %04x:%06x:%04x/%02x:%08x\n", cwcycle2str(pcache->cwcycle),
pcache->caid, pcache->provid, pcache->sid, pcache->tag, pcache->hash,
thereq->caid, thereq->provid, thereq->sid, thereq->tag, thereq->hash );
}
#endif
}
}
pcache = pcache->next;
if (pcache==cachetab[index]) break;
}
return result;
}
// -1: bad cw
// 0: nothing to do
// 1: dcw set
// 2: dcw set & sent to pipe
int cache_setdcw( struct cache_data *req, uint8_t cw[16], cwcycle_t cwcycle, int peerid )
{
if ( !acceptDCW(cw) ) return -1;
// Search for Cache data
struct cw_cache_data *cwdata = NULL;
struct cache_data *pcache = cache_fetch( req );
if (pcache==NULL) pcache = cache_new( req );
else {
if (!pcache->tag) pcache->tag = req->tag; // set tag if not set (coming from cahceex)
if (!pcache->provid && req->provid) pcache->provid = req->provid; // set provid if not set (coming from csp)
// check for dcw
cwdata = pcache->cwdata;
while (cwdata) {
if ( dcwcmp16(cwdata->cw, cw) ) break;
cwdata = cwdata->next;
}
}
// add new if not found
if (!cwdata) {
cwdata = malloc( sizeof(struct cw_cache_data) );
memset( cwdata, 0, sizeof(struct cw_cache_data) );
memcpy(cwdata->cw, cw, 16);
cwdata->status = 0;
cwdata->cwcycle = NO_CYCLE;
cwdata->peerid = peerid;
cwdata->next = pcache->cwdata;
pcache->cwdata = cwdata;
}
cwdata->nbpeers++;
if (cwdata->status&DCW_ERROR) return DCW_ERROR;
// TEST for min Peers
if (cwdata->nbpeers!=cfg.cache.threshold) return DCW_ERROR | DCW_SKIP;
// ACCEPTED
if (cfg.cache.dcwcheck2) cache_fetch_goodcw2(pcache, cw, peerid);
if (cfg.cache.dcwcheck3) cache_fetch_goodcw3(pcache, cw, peerid);
// Half Nulled CW
char nullcw[8] = "\0\0\0\0\0\0\0\0";
if ( !dcwcmp8(cw,nullcw) && !dcwcmp8(cw+8,nullcw) ) {
if ( !isnullDCW(pcache->prevcw) ) {
if ( ( (pcache->cwcycle==CW1CYCLE) && dcwcmp8(pcache->prevcw,cw) && !similarcw(pcache->prevcw+8,cw+8) ) ||
( (pcache->cwcycle==CW0CYCLE) && !similarcw(pcache->prevcw,cw) && dcwcmp8(pcache->prevcw+8,cw+8) ) ) {
// update new dcw
cwdata->status |= DCW_CYCLE;
cwdata->cwcycle = pcache->cwcycle;
cwdata->peerid = peerid;
if ( (pcache->flags&CACHE_FLAG_SENDPIPE) && !(cwdata->status&DCW_SENT) ) {
pipe_cache2ecm_find_success(pcache, cw, peerid);
cwdata->status |= DCW_SENT;
}
return cwdata->status;
}
}
// cache without cw1 cycle
if (cfg.cache.filter && (cwcycle==NO_CYCLE) ) {
cwdata->status |= cache_fetch_goodcw(pcache, cw, &cwcycle);
cwdata->cwcycle = cwcycle;
cwdata->peerid = peerid;
if (!(cwdata->status&DCW_CYCLE)) return cwdata->status; //XXX
}
else {
// update new dcw
cwdata->status |= DCW_CYCLE;
cwdata->cwcycle = cwcycle;
cwdata->peerid = peerid;
}
// Check Cycle
if ( (pcache->cwcycle!=NO_CYCLE)&&(pcache->cwcycle!=cwcycle) ) {
cwdata->status |= DCW_ERROR;
return cwdata->status;
}
}
else {
// half nulled cw: exit if non-nds
if ( (req->caid>>8)!=9 ) {
cwdata->status |= DCW_ERROR;
return cwdata->status;
}
//
if ( dcwcmp8(cw,nullcw) ) cwcycle = CW1CYCLE;
else if ( dcwcmp8(cw+8,nullcw) ) cwcycle = CW0CYCLE;
// update new dcw
cwdata->status |= DCW_CYCLE;
cwdata->cwcycle = cwcycle;
cwdata->peerid = peerid; // CSP CACHE
}
if ( (pcache->flags&CACHE_FLAG_SENDPIPE) && !(cwdata->status&DCW_SENT) ) {
cwdata->status |= DCW_SENT;
pipe_cache2ecm_find_success(pcache, cw, peerid);
#ifdef TESTCHANNEL
int testchannel = ( (pcache->caid==cfg.testchn.caid) && (!pcache->provid || pcache->provid==cfg.testchn.provid) && (pcache->sid==cfg.testchn.sid) );
if (testchannel) {
char dump[64];
array2hex( cw, dump, 16);
fdebugf(" (Cache->Setdcw) ch %04x:%06x:%04x/%02x:%08x -> %s (%s)\n", pcache->caid, pcache->provid, pcache->sid, pcache->tag, pcache->hash,
dump, cwcycle2str(pcache->cwcycle) );
}
#endif
}
return cwdata->status;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// RECEIVE MESSAGES
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void cache_recvmsg(struct cacheserver_data *cache)
{
unsigned int recv_ip;
unsigned short recv_port;
unsigned char buf[2048];
char str[1024];
struct sockaddr_in si_other;
socklen_t slen=sizeof(si_other);
struct cachepeer_data *peer;
int received = recvfrom( cache->handle, buf, sizeof(buf), 0, (struct sockaddr*)&si_other, &slen);
if ( (received<2)||(received>512) ) return;
memcpy( &recv_ip, &si_other.sin_addr, 4);
recv_port = ntohs(si_other.sin_port);
#ifdef DEBUG_NETWORK2
if (flag_debugnet) {
debugf(getdbgflag(DBG_CACHE,0,0)," cache: recv data (%d) from address (%s:%d)\n", received, ip2string(recv_ip), recv_port );
debughex(buf,received);
}
#endif
// Store Data
struct cache_data req;
switch(buf[0]) {
case TYPE_REQUEST:
// Check Peer
peer = getpeerbyaddr(cache, recv_ip,recv_port);
if (!peer) break;
// Check Status
if (IS_DISABLED(peer->flags)) break;
// Get DATA
req.tag = buf[1];
req.sid = (buf[2]<<8) | buf[3];
req.onid = (buf[4]<<8) | buf[5];
req.caid = (buf[6]<<8) | buf[7];
req.hash = (buf[8]<<24) | (buf[9]<<16) | (buf[10]<<8) |buf[11];
req.provid = 0;
pthread_mutex_lock( &prg.lockcache );
// Check Cache Request
if ( cache_check(&req) ) {
peer->reqnb++;
// ADD CACHE
struct cache_data *pcache = cache_fetch( &req );
if (pcache==NULL) pcache = cache_new( &req );
else {
if (!pcache->tag) pcache->tag = req.tag; // set tag if not set (coming from cahceex)
if (!pcache->provid && req.provid) pcache->provid = req.provid; // set provid if not set (coming from csp)
if ( cfg.cache.forward || ((peer->ismultics)&&(peer->protocol&BIT_CACHE_HACK)) )
if ( pcache->cwdata && !(pcache->flags&CACHE_FLAG_SENDPIPE) ) {
struct cw_cache_data *cwdata = pcache->cwdata;
while (cwdata) {
if (!(cwdata->status&DCW_ERROR)) {
cache_send_reply( pcache, peer, cwdata->cw);
if (cfg.cache.forward) peer->sentrep++;
}
cwdata = cwdata->next;
}
}
}
}
pthread_mutex_unlock( &prg.lockcache );
break;
case TYPE_REPLY:
// Check Peer
peer = getpeerbyaddr(cache, recv_ip,recv_port);
if (!peer) break;
// Check Status
if (IS_DISABLED(peer->flags)) break;
// Check Integrity
if (buf[12]!=buf[1]) break;
// SetUp Request
req.tag = buf[1];
req.sid = (buf[2]<<8) | buf[3];
req.onid = (buf[4]<<8) | buf[5];
req.caid = (buf[6]<<8) | buf[7];
req.hash = (buf[8]<<24) | (buf[9]<<16) | (buf[10]<<8) |buf[11];
req.provid = 0;
pthread_mutex_lock( &prg.lockcache );
// Check Cache Request
if ( cache_check(&req) ) {
// check for length
if ( received>=29 ) {
uint8_t cw[16];
peer->repok++;
memcpy(cw, buf+13, 16);
// Search for Cache data
cwcycle_t cwcycle = NO_CYCLE;
if ( peer->fwd && (received==30) ) cwcycle = buf[29];
int status = cache_setdcw(&req,cw,cwcycle,peer->id|PEER_CSP);
if ( !(status&DCW_ERROR) ) { // && (status&DCW_CYCLE) ) {
if (!peer->fwd) {
cache_send_fwdreply( &req, cw, cwcycle);
}
}
}
}
pthread_mutex_unlock( &prg.lockcache );
break;
case TYPE_RESENDREQ:
// Check Peer
peer = getpeerbyaddr(cache, recv_ip,recv_port);
if (!peer) break;
// Check Status
if (IS_DISABLED(peer->flags)) break;
// Check Packer length
if (received<16) break;
// Good Packet
struct cache_data req;
req.tag = buf[5];
req.sid = (buf[6]<<8) | buf[7];
req.onid = (buf[8]<<8) | buf[9];
req.caid = (buf[10]<<8) | buf[11];
req.hash = (buf[12]<<24) | (buf[13]<<16) | (buf[14]<<8) | buf[15];
req.provid = 0;
//
pthread_mutex_lock( &prg.lockcache );
// Check Cache Request
if ( cache_check(&req) ) {
struct cache_data *pcache = cache_fetch( &req );
if (pcache!=NULL) {
buf[4] = TYPE_REPLY;
buf[16] = buf[5];
struct cw_cache_data *cwdata = pcache->cwdata;
while (cwdata) {
if (!(cwdata->status&DCW_ERROR)) {
memcpy( buf+17, cwdata->cw, 16);
sendtopeer( peer, buf+4, 29);
}
cwdata = cwdata->next;
}
}
}
//
pthread_mutex_unlock( &prg.lockcache );
break;
case TYPE_PINGREQ:
// Check Peer
peer = cache->peer;
int port = (buf[11]<<8)|buf[12];
struct cachepeer_data *peerip = NULL;
while (peer) {
if (peer->host->ip==recv_ip) {
peerip = peer;
if (peer->port==port) break; // Found
}
peer = peer->next;
}
if (!peer) {
if (peerip) {
// Check for peer reuse
peer = cache->peer;
while (peer) {
if ( (peer->port==port) && !strcmp(peer->host->name,peerip->host->name) ) break;
peer = peer->next;
}
if (!peer) {
if (peerip->port==0) peerip->port = port;
else {
// add new peer
peer = malloc( sizeof(struct cachepeer_data) );
memset( peer, 0, sizeof(struct cachepeer_data) );
peer->host = peerip->host;
peer->port = port;
peer->outsock = cache->handle; //CreateClientSockUdp(0,0);
peer->runtime = 1;
peer->fblock0onid = peerip->fblock0onid;
peer->id = cfg.cache.peerid;
cfg.cache.peerid++;
peer->flags = FLAG_CACHE_SENDREQ | FLAG_CACHE_SENDREP;
peer->next = peerip->next;
peerip->next = peer;
if (!peerip->autoadd || !cfg.cache.autoadd) {
peer->flags |= FLAG_DISABLE;
// Check for extended reply ( Program Name/Version )
int index = 13;
while (received>index) {
if ( (index+buf[index+1]+2)>received ) break;
switch(buf[index]) {
case 0x01:
if (buf[index+1]<32) { memcpy(peer->program, buf+index+2, buf[index+1]); peer->program[buf[index+1]] = 0; }
break;
case 0x02:
if (buf[index+1]<32) { memcpy(peer->version, buf+index+2, buf[index+1]); peer->version[buf[index+1]] = 0; }
break;
}
index += 2+buf[index+1];
}
}
else debugf(getdbgflag(DBG_CACHE,0,0), " cache: new peer (%s:%d)\n", peer->host->name, peer->port );
}
}
else {
peer->host->checkiptime = 0;
}
}
else if (cfg.cache.autoadd) {
// add new peer
peer = malloc( sizeof(struct cachepeer_data) );
memset( peer, 0, sizeof(struct cachepeer_data) );
peer->flags = FLAG_CACHE_SENDREQ | FLAG_CACHE_SENDREP;
// ADD HOST
struct host_data *host = add_host( &cfg, ip2string(recv_ip) );
host->ip = recv_ip;
peer->host = host;
peer->port = port;
peer->id = cfg.cache.peerid;
peer->srvid = cache->id;
peer->outsock = cache->handle; //CreateClientSockUdp(0,0);
peer->runtime = 1;
cfg.cache.peerid++;
cfg_addcachepeer(cache, peer);
if (!cfg.cache.autoenable) {
peer->flags |= FLAG_DISABLE;
// Check for extended reply ( Program Name/Version )
int index = 13;
while (received>index) {
if ( (index+buf[index+1]+2)>received ) break;
switch(buf[index]) {
case 0x01:
if (buf[index+1]<32) { memcpy(peer->program, buf+index+2, buf[index+1]); peer->program[buf[index+1]] = 0; }
break;
case 0x02:
if (buf[index+1]<32) { memcpy(peer->version, buf+index+2, buf[index+1]); peer->version[buf[index+1]] = 0; }
break;
}
index += 2+buf[index+1];
}
}
else debugf(getdbgflag(DBG_CACHE,0,0), " cache: new peer (%s:%d)\n", peer->host->name, peer->port );
}
else debugf( getdbgflag(DBG_CACHE,0,0), " cache: Alert! unknown peer (%s:%d)\n", ip2string(recv_ip), port );
}
//
if (peer) {
// Check Status
if (IS_DISABLED(peer->flags)) break;
// Set Defaults
memset( peer->cards, 0, sizeof(peer->cards) );
peer->protocol = 0; // Normal CSP Protocol
peer->program[0] = 0;
peer->version[0] = 0;
// Check for extended reply ( Program Name/Version )
int index = 13;
while (received>index) {
if ( (index+buf[index+1]+2)>received ) break;
switch(buf[index]) {
case 0x01:
if (buf[index+1]<32) { memcpy(peer->program, buf+index+2, buf[index+1]); peer->program[buf[index+1]] = 0; }
break;
case 0x02:
if (buf[index+1]<32) { memcpy(peer->version, buf+index+2, buf[index+1]); peer->version[buf[index+1]] = 0; }
break;
}
index += 2+buf[index+1];
}
// Set Default Reply
buf[0] = TYPE_PINGRPL;
// Check for New Protocol
if ( buf[1]=='M' && buf[2]=='C' ) {
peer->protocol = buf[3];
if (peer->protocol&1) {
buf[0] = TYPE_HELLO_ACK;
// Decode CRC
buf[13] = cache->port>>8;
buf[14] = cache->port;
fase( buf+11, buf+6);
}
} else if ( !peer->csp || (received>13) ) { peer->flags |= FLAG_DISABLE; break; }
sendtopeer( peer, buf, 9);
// Check for activity
if (peer->recvport!=recv_port) {
peer->ping = 0;
peer->recvport = recv_port;
peer->ismultics = 0;
}
}
break;
case TYPE_PINGRPL:
// Get Peer
peer = cache->peer;
int peerid = (buf[4]<<8) | buf[5];
while (peer) {
if ( (peer->host->ip==recv_ip)&&(peer->id==peerid) ) {
peer->protocol = 0;
peer->recvport = recv_port;
peer->lastpingrecv = GetTickCount();
if (peer->ping>0)
peer->ping = (peer->ping+peer->lastpingrecv-peer->lastpingsent)/2;
else {
if (!peer_doublecheck(cache,peer)) break;
debugf(getdbgflag(DBG_CACHE,0,peer->id), " cache: Peer (%s:%d) come Online\n", peer->host->name, peer->port );
peer->ping = peer->lastpingrecv-peer->lastpingsent;
//ipeer_update(cache);
}
peer->ping++;
break;
}
peer = peer->next;
}
break;
#ifdef NEWCACHE
case TYPE_HELLO_ACK:
// Get Peer
peerid = (buf[4]<<8) | buf[5];
peer = cache->peer;
while (peer) {
if ( (peer->host->ip==recv_ip)&&(peer->id==peerid) ) {
// Check for private new cache
uint8_t k[4]; k[0] = cache->port>>8; k[1] = cache->port; k[2]=peer->port>>8; k[3]=peer->port;
fase( k, peer->crc);
if ( (peer->crc[0]==buf[6])&&(peer->crc[1]==buf[7])&&(peer->crc[2]==buf[8]) ) peer->ismultics =1; else peer->ismultics = 0;
//
peer->recvport = recv_port;
peer->lastpingrecv = GetTickCount();
if (peer->ping>0)
peer->ping = (peer->ping+peer->lastpingrecv-peer->lastpingsent)/2;
else {
if (!peer_doublecheck(cache,peer)) break;
debugf(getdbgflag(DBG_CACHE,0,peer->id), " cache: Peer (%s:%d) come Online*\n", peer->host->name, peer->port );
peer->ping = peer->lastpingrecv-peer->lastpingsent;
//ipeer_update(cache);
}
peer->ping++;
//debugf(getdbgflag(DBG_CACHE,0,peer->id), " cache: sending card data to peer (%s:%d)\n", peer->host->name, peer->port );
// Send CARDS DATA
buf[0] = TYPE_CARD_LIST;
buf[1] = 1; // Reset Cards
int pos = 2;
//sendtopeer( peer, buf, pos);
if (peer->sharelimits[0].caid!=0xffff) {
int i;
for (i=0; i<100; i++) {
if (peer->sharelimits[i].caid==0xffff) break;
uint32_t caprov = (peer->sharelimits[i].caid<<16)|(peer->sharelimits[i].provid);
buf[pos] = caprov>>24;
buf[pos+1] = caprov>>16;
buf[pos+2] = caprov>>8;
buf[pos+3] = caprov;
pos +=4;
if (pos>400) {
sendtopeer( peer, buf, pos);
buf[0] = TYPE_CARD_LIST;
buf[1] = 0; // no Reset
pos = 2;
}
}
if (pos>2) {
sendtopeer( peer, buf, pos);
}
}
else
{
struct cardserver_data *cs = cfg.cardserver;
while (cs) {
int i;
if (cs->option.fallowcache)
for (i=0; i<cs->card.nbprov; i++) {
uint32_t caprov = (cs->card.caid<<16)|(cs->card.prov[i].id);
buf[pos] = caprov>>24;
buf[pos+1] = caprov>>16;
buf[pos+2] = caprov>>8;
buf[pos+3] = caprov;
pos +=4;
if (pos>400) {
sendtopeer( peer, buf, pos);
buf[0] = TYPE_CARD_LIST;
buf[1] = 0; // no Reset
pos = 2;
}
}
cs = cs->next;
}
if (pos>2) {
sendtopeer( peer, buf, pos);
}
}
break;
}
peer = peer->next;
}
break;
case TYPE_CARD_LIST:
// Check Peer
peer = getpeerbyaddr(cache, recv_ip,recv_port);
if (!peer) break;
// reset cards
int idx = 0;
if (buf[1]&1) memset( peer->cards, 0, sizeof(peer->cards) );
else for (idx=0; idx<1024; idx++) if (!peer->cards[idx]) break;
//
int totalcards = (received-2)/4;
int j=0;
while ( (j<totalcards)&&(idx<1024) ){
peer->cards[idx] = (buf[2+j*4]<<24)|(buf[3+j*4]<<16)|(buf[4+j*4]<<8)|(buf[5+j*4]);
j++; idx++;
}
peer->nbcards = idx;
// Arrange Cards
int i;
for (i=0; i<(idx-1); i++)
for (j=i+1; j<idx; j++)
if ( peer->cards[i] > peer->cards[j] ) { uint32_t x=peer->cards[i]; peer->cards[i] = peer->cards[j]; peer->cards[j] = x; }
break;
case TYPE_KEEPALIVE:
// Check Peer
peer = getpeerbyaddr(cache, recv_ip,recv_port);
if (!peer) break;
// Check Status
if (IS_DISABLED(peer->flags)) break;
if (!peer->nbcards) break;
// Send Reply
buf[0] = TYPE_KEEPALIVE_ACK;
sendtopeer( peer, buf, received);
break;
case TYPE_KEEPALIVE_ACK:
// Check Peer
peer = getpeerbyaddr(cache, recv_ip,recv_port);
if (!peer) break;
// Check Status
if (IS_DISABLED(peer->flags)) break;
//
peer->lastpingrecv = GetTickCount();
if (peer->ping>0)
peer->ping = (peer->ping+peer->lastpingrecv-peer->lastpingsent)/2;
else
peer->ping = peer->lastpingrecv-peer->lastpingsent;
peer->ping++;
break;
case TYPE_SMS:
peer = getpeerbyaddr(cache, recv_ip,recv_port);
if (!peer) break;
if (received<6) break;
uint32_t hash = (buf[1]<<24) | (buf[2]<<16) | (buf[3]<<8) | (buf[4]);
buf[received] = 0;
//
peer_check_messages( peer );
// Create data
struct sms_data *sms = malloc( sizeof(struct sms_data) );
stringtohtml( buf+5, sms->msg);
// strcpy( sms->msg, (char*)buf+5);
sms->hash = hash;
sms->status = 0; // bit 0 (0:in,1:out) bit 1 (0:unread/unAck, 1:read/ack)
time (&sms->rawtime);
sms->next = peer->sms;
peer->sms = sms;
// SEND ACK
buf[0] = TYPE_SMS_ACK;
sendtopeer( peer, buf, 5 );
// debug
debugf(getdbgflag(DBG_CACHE,0,0)," cache: SMS from peer (%s:%d)\n", peer->host->name, peer->port);
// print to sms file
save_sms( sms, peer);
break;
case TYPE_SMS_ACK:
peer = getpeerbyaddr(cache, recv_ip,recv_port);
if (!peer) break;
if (received!=5) break;
if (!peer->sms) break;
hash = (buf[1]<<24) | (buf[2]<<16) | (buf[3]<<8) | (buf[4]);
// Search for data
sms = peer->sms;
while (sms) {
if ( (sms->hash==hash)&&(sms->status==1) ) {
debugf(getdbgflag(DBG_CACHE,0,0)," cache: SMS ACK from peer (%s:%d)\n", peer->host->name, peer->port);
sms->status = 3;
}
sms = sms->next;
}
break;
#endif
case TYPE_VERSION:
peer = getpeerbyaddr(cache, recv_ip,recv_port);
if (peer) {
buf[0] = TYPE_VERSION_ACK;
buf[1] = 'r';
buf[2] = '0'+(REVISION/10);
buf[3] = '0'+(REVISION%10);
sendtopeer( peer, buf, 4 );
}
break;
case TYPE_EXTENDED:
if (buf[1]=='V') { // Version
buf[0] = TYPE_EXTENDED_ACK;
buf[2] = 'r';
buf[3] = '0'+(REVISION/10);
buf[4] = '0'+(REVISION%10);
sendtoip( cache->handle, recv_ip, recv_port, buf, 5);
}
break;
case TYPE_UNKNOWN:
break;
default:
if (received>100) array2hex( buf, str, 100); else array2hex( buf, str, received);
debugf(getdbgflag(DBG_CACHE,0,0)," cache: Unknown message from %s (%d) : %s\n", ip2string(recv_ip), received, str );
#ifdef NEWCACHE
peer = getpeerbyaddr(cache, recv_ip,recv_port);
if ( peer && (peer->protocol&1) ) {
buf[1] = buf[0];
buf[0] = TYPE_UNKNOWN;
sendtopeer( peer, buf, 2 );
}
#endif
break;
}
}
void cache_pipe_recvmsg()
{
uint8_t buf[64];
uint8_t cw[16];
struct cache_data req;
struct cache_data *pcache;
int len = pipe_recv( prg.pipe.cache[0], buf );
if (len<=0) return;
switch (buf[0]) {
case PIPE_CACHE_FIND:
get_ecm2cache(buf , &req, req.prevcw);
//debugf(0, " Get PIPE_CACHE_FIND: %04x:%06x:%04x:%08x\n", req.caid, req.provid, req.sid, req.hash);
pcache = cache_fetch( &req );
if (pcache==NULL) {
pcache = cache_new( &req );
pcache->ecm = req.ecm;
pcache->cwcycle = req.cwcycle;
#ifdef CACHEEX
if (len==16+sizeof(void*)+16+16) memcpy( pcache->prevcw, req.prevcw, 16);
memcpy( pcache->ecmd5, req.ecmd5, 16 );
#else
if (len==16+sizeof(void*)+16) memcpy( pcache->prevcw, req.prevcw, 16);
#endif
pcache->flags |= CACHE_FLAG_SENDPIPE;
// Send find failed
pipe_cache2ecm_find_failed(pcache);
}
else {
pcache->ecm = req.ecm;
pcache->tag = req.tag; // set tag if not set (coming from cahceex)
pcache->provid = req.provid; // set provid if not set (coming from csp)
pcache->cwcycle = req.cwcycle;
pcache->provid = req.provid;
#ifdef CACHEEX
if (len==16+sizeof(void*)+16+16) memcpy( pcache->prevcw, req.prevcw, 16);
memcpy( pcache->ecmd5, req.ecmd5, 16 );
#else
if (len==16+sizeof(void*)+16) memcpy( pcache->prevcw, req.prevcw, 16);
#endif
pcache->flags |= CACHE_FLAG_SENDPIPE;
// Check stored cw with status = 0, look for same cycle
if ( !isnullDCW(pcache->prevcw) ) {
// look for consecutif cw & same cycle
struct cw_cache_data *cwdata = pcache->cwdata;
while (cwdata) {
if ( !(cwdata->status&DCW_ERROR) && !(cwdata->status&DCW_SENT) )
if ( (cwdata->status&DCW_CYCLE)&&(cwdata->nbpeers>=cfg.cache.threshold) ) {
if ( pcache->cwcycle==cwdata->cwcycle ) {
if ( ( (pcache->cwcycle==CW1CYCLE) && dcwcmp8(pcache->prevcw,cwdata->cw) && !similarcw(pcache->prevcw+8,cwdata->cw+8) ) ||
( (pcache->cwcycle==CW0CYCLE) && !similarcw(pcache->prevcw,cwdata->cw) && dcwcmp8(pcache->prevcw+8,cwdata->cw+8) ) ) {
cwdata->status |= DCW_SENT;
pipe_cache2ecm_find_success(pcache, cwdata->cw, cwdata->peerid );
}
}
}
cwdata = cwdata->next;
}
// look for consecutif cw only
cwdata = pcache->cwdata;
while (cwdata) {
if ( !(cwdata->status&DCW_ERROR) && !(cwdata->status&DCW_SENT) )
if ( !(cwdata->status&DCW_CYCLE) && (cwdata->nbpeers>=cfg.cache.threshold) ) {
if ( ( (pcache->cwcycle==CW1CYCLE) && dcwcmp8(pcache->prevcw,cwdata->cw) && !similarcw(pcache->prevcw+8,cwdata->cw+8) ) ||
( (pcache->cwcycle==CW0CYCLE) && !similarcw(pcache->prevcw,cwdata->cw) && dcwcmp8(pcache->prevcw+8,cwdata->cw+8) ) ) {
cwdata->status |= DCW_SENT;
pipe_cache2ecm_find_success(pcache, cwdata->cw, cwdata->peerid );
}
}
cwdata = cwdata->next;
}
}
else { // NO PREVIOUS CW
// cached cw with cycle
struct cw_cache_data *cwdata = pcache->cwdata;
while (cwdata) {
if ( !(cwdata->status&DCW_ERROR) && !(cwdata->status&DCW_SENT) )
if ( (cwdata->status&DCW_CYCLE)&&(cwdata->nbpeers>=cfg.cache.threshold) ) {
if ( (pcache->cwcycle==NO_CYCLE)||(pcache->cwcycle==cwdata->cwcycle) ) {
cwdata->status |= DCW_SENT;
pipe_cache2ecm_find_success(pcache, cwdata->cw, cwdata->peerid );
}
}
cwdata = cwdata->next;
}
// no cycle for cached cw
cwdata = pcache->cwdata;
while (cwdata) {
if ( !(cwdata->status&DCW_ERROR) && !(cwdata->status&DCW_SENT) )
if ( !(cwdata->status&DCW_CYCLE) && (cwdata->nbpeers>=5) ) {
cwdata->status |= DCW_SENT;
pipe_cache2ecm_find_success(pcache, cwdata->cw, cwdata->peerid );
}
cwdata = cwdata->next;
}
}
}
break;
case PIPE_CACHE_REQUEST:
get_ecm2cache(buf , &req, NULL);
//debugf(0, " Get PIPE_CACHE_REQUEST: %04x:%06x:%04x:%08x\n", req.caid, req.provid, req.sid, req.hash);
pcache = cache_fetch( &req );
if (pcache==NULL) pcache = cache_new( &req );
else {
pcache->tag = req.tag; // set tag if not set (coming from cahceex)
pcache->provid = req.provid; // set provid if not set (coming from csp)
}
pcache->ecm = req.ecm;
pcache->flags |= CACHE_FLAG_SENDPIPE;
// Send Request if not dcw sent
if (!(pcache->flags&CACHE_FLAG_REQSENT)) {
pcache->flags |= CACHE_FLAG_REQSENT;
cfg.cache.req++;
cache_send_request(pcache,NULL);
}
break;
case PIPE_CACHE_REPLY:
get_ecm2cache(buf , &req, cw);
//debugf(0, " Get PIPE_CACHE_REPLY: %04x:%06x:%04x:%08x\n", req.caid, req.provid, req.sid, req.hash);
pcache = cache_fetch( &req );
if (pcache==NULL) pcache = cache_new( &req );
else {
pcache->tag = req.tag; // set tag if not set (coming from cahceex)
pcache->provid = req.provid; // set provid if not set (coming from csp)
}
//Check & update DCW
struct cw_cache_data *cwdata = pcache->cwdata;
while (cwdata) {
if ( dcwcmp16(cwdata->cw, cw) ) break;
cwdata = cwdata->next;
}
// ADD if not found
if (!cwdata) {
struct cw_cache_data *cwdata = malloc( sizeof(struct cw_cache_data) );
memset( cwdata, 0, sizeof(struct cw_cache_data) );
memcpy(cwdata->cw, cw, 16);
//cwdata->cwcycle = NO_CYCLE;
//cwdata->peerid = peerid;
cwdata->next = pcache->cwdata;
pcache->cwdata = cwdata;
if (cfg.cache.dcwcheck2) cache_fetch_goodcw2(pcache, cw, 0);
if (cfg.cache.dcwcheck3) cache_fetch_goodcw3(pcache, cw, 0);
}
//cwdata->status |= DCW_CYCLE;
// Send Reply
if ( !(pcache->flags&CACHE_FLAG_REPSENT) ) cfg.cache.rep++;
pcache->flags |= CACHE_FLAG_REPSENT;
cache_send_reply(pcache, NULL, cw);
break;
case PIPE_CACHE_RESENDREQ:
get_ecm2cache(buf , &req, NULL);
/*
pcache = cache_fetch( &req );
if (pcache==NULL) pcache = cache_new( &req );
else {
struct cw_cache_data *cwdata = pcache->cwdata;
while (cwdata) {
pipe_cache2ecm_find_success(pcache, cwdata->cw, cwdata->peerid );
cwdata = cwdata->next;
}
}
*/
cache_send_resendreq(&req);
break;
}
}
void cache_check_peers(struct cacheserver_data *cache)
{
struct cachepeer_data *peer = cache->peer;
while (peer) {
if (!IS_DISABLED(peer->flags))
if ( (peer->host->ip)&&(peer->port) ) {
uint32_t ticks = GetTickCount();
if (peer->ping==0) { // inactive
if ( (!peer->lastpingsent)||((peer->lastpingsent+9000)<ticks) ) { // send every 15s
cache_send_ping(cache, peer);
peer->lastpingsent = ticks;
peer->lastpingrecv = 0;
peer->ping = -1;
}
}
else if (peer->ping==-1) { // inactive
if ( (!peer->lastpingsent)||((peer->lastpingsent+19000)<ticks) ) { // send every 15s
cache_send_ping(cache, peer);
peer->lastpingsent = ticks;
peer->lastpingrecv = 0;
peer->ping = -2;
}
}
else if (peer->ping==-2) { // inactive
if ( (!peer->lastpingsent)||((peer->lastpingsent+29000)<ticks) ) { // send every 15s
cache_send_ping(cache, peer);
peer->lastpingsent = ticks;
peer->lastpingrecv = 0;
peer->ping = -3;
}
}
else if (peer->ping<=-3) { // inactive
if ( (!peer->lastpingsent)||((peer->lastpingsent+59000)<ticks) ) { // send every 15s
cache_send_ping(cache, peer);
peer->lastpingsent = ticks;
peer->lastpingrecv = 0;
}
}
else if (peer->ping>0) {
if ( (!peer->lastpingrecv)&&((peer->lastpingsent+9000)<ticks) ) {
if (peer->lastpingnb==1) {
#ifdef NEWCACHE
cache_send_keepalive(cache, peer);
#else
cache_send_ping(cache, peer);
#endif
peer->lastpingsent = ticks;
peer->lastpingnb = 2;
}
else if (peer->lastpingnb==2) {
#ifdef NEWCACHE
cache_send_keepalive(cache, peer);
#else
cache_send_ping(cache, peer);
#endif
peer->lastpingsent = ticks;
peer->lastpingnb = 3;
}
else if (peer->lastpingnb==3) {
cache_send_ping(cache, peer);
peer->lastpingsent = ticks;
peer->lastpingrecv = 0;
peer->ping = 0;
peer->host->checkiptime = 0; // maybe ip changed
//ipeer_update(cache);
}
}
else if ( (peer->lastpingsent+60000)<ticks ) { // send every 75s
#ifdef NEWCACHE
cache_send_keepalive(cache, peer);
#else
cache_send_ping(cache, peer);
#endif
peer->lastpingsent = ticks;
peer->lastpingrecv = 0;
peer->lastpingnb = 1;
}
}
}
peer = peer->next;
}
}
///////////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////////
#ifdef EPOLL_CACHE
void *cache_thread(void *param)
{
prg.pid_cache = syscall(SYS_gettid);
prg.tid_cache = pthread_self();
prctl(PR_SET_NAME,"Cache RecvMSG Thread",0,0,0);
sleep(3);
int i;
struct epoll_event evlist[MAX_EPOLL_EVENTS]; // epoll recv events
uint32_t chkticks = 0;
while (!prg.restart) {
// Check Peers Ping
if ( GetTickCount()>(chkticks+5000) ) {
struct cacheserver_data *cache = cfg.cache.server;
while (cache) {
cache_check_peers(cache);
cache = cache->next;
}
chkticks = GetTickCount();
}
int ready = epoll_wait( prg.epoll.cache, evlist, MAX_EPOLL_EVENTS, 1001);
if (ready == -1) {
if ( (errno==EINTR)||(errno==EAGAIN) ) {
usleep(1000);
continue;
}
else {
usleep(99000);
debugf(DBG_ERROR,"Err! epoll_wait (%d)", errno);
}
}
else if (ready==0) continue; // timeout
for (i=0; i < ready; i++) {
if ( evlist[i].events & (EPOLLIN|EPOLLPRI) ) cache_recvmsg(evlist[i].data.ptr);
}
}
return NULL;
}
#else
void *cache_thread(void *param)
{
prg.pid_cache = syscall(SYS_gettid);
prg.tid_cache = pthread_self();
prctl(PR_SET_NAME,"Cache RecvMSG Thread",0,0,0);
uint32_t chkticks = 0;
while (!prg.restart) {
// Check Peers Ping
if ( GetTickCount()>(chkticks+3000) ) {
struct cacheserver_data *cache = cfg.cache.server;
while (cache) {
cache_check_peers(cache);
cache = cache->next;
}
chkticks = GetTickCount();
}
struct pollfd pfd[100];
int pfdcount = 0;
#ifndef THREAD_CACHE_PIPE
pfd[pfdcount].fd = prg.pipe.cache[0];
pfd[pfdcount].events = POLLIN | POLLPRI;
pfdcount++;
#endif
struct cacheserver_data *cache = cfg.cache.server;
while (cache) {
if (cache->handle>0) {
cache->ipoll = pfdcount;
pfd[pfdcount].fd = cache->handle;
pfd[pfdcount++].events = POLLIN | POLLPRI;
} else cache->ipoll = -1;
cache = cache->next;
}
int retval = poll(pfd, pfdcount, 3001);
if ( retval>0 ) {
#ifndef THREAD_CACHE_PIPE
if ( pfd[0].revents & (POLLIN|POLLPRI) ) {
pthread_mutex_lock( &prg.lockcache );
cache_pipe_recvmsg();
pthread_mutex_unlock( &prg.lockcache );
}
#endif
struct cacheserver_data *cache = cfg.cache.server;
while (cache) {
if ( (cache->handle>0)&&(cache->ipoll>=0)&&(cache->handle==pfd[cache->ipoll].fd) )
if ( pfd[cache->ipoll].revents & (POLLIN|POLLPRI) ) {
//pthread_mutex_lock( &prg.lockcache );
cache_recvmsg(cache);
//pthread_mutex_unlock( &prg.lockcache );
}
cache = cache->next;
}
} else usleep( 99000 );
}
//close(cfg.cache.handle);
return NULL;
}
#endif
///////////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////////
#ifdef THREAD_CACHE_PIPE
void *cache_pipe_thread(void *param)
{
prg.pid_cache_pipe = syscall(SYS_gettid);
prg.tid_cache_pipe = pthread_self();
prctl(PR_SET_NAME,"Cache Pipe Thread",0,0,0);
while (!prg.restart) {
struct pollfd pfd;
pfd.fd = prg.pipe.cache[0];
pfd.events = POLLIN | POLLPRI;
int retval = poll(&pfd, 1, 3031);
if ( retval>0 ) {
pthread_mutex_lock( &prg.lockcache );
cache_pipe_recvmsg();
pthread_mutex_unlock( &prg.lockcache );
}
else usleep( 99000 );
}
return NULL;
}
#endif
///////////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////////
int start_thread_cache()
{
#ifdef THREAD_CACHE_PIPE
create_thread(&prg.tid_cache, (threadfn)cache_pipe_thread,NULL);
#endif
create_thread(&prg.tid_cache, (threadfn)cache_thread,NULL);
return 0;
}