./ MultiCS.r82 / loadbalance.c
///////////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////////
// 0: different ; 1:~equivalent
int cs_cmp_card( struct cs_card_data *card, struct cardserver_data *cs)
{
int i,j,found;
int nbsame = 0;
int nbdiff = 0;
if (card->caid!=cs->card.caid) return 0;
/*
if ( ((card->caid & 0xff00)==0x1800)
|| ((card->caid & 0xff00)==0x0900)
|| ((card->caid & 0xff00)==0x0b00) ) return 1;
*/
if ( ((card->caid & 0xff00)!=0x0100) && ((card->caid & 0xff00)!=0x0500) ) return 1;
for(i=0; i<card->nbprov;i++) {
found = 0;
for(j=0; j<cs->card.nbprov;j++)
if (card->prov[i]==cs->card.prov[j].id) {
found = 1;
break;
}
if (found) nbsame++; else nbdiff++;
}
if ( (nbsame==card->nbprov)||(nbsame==cs->card.nbprov) ) return 1;
return 0;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
int match_card( uint16_t caid, uint32_t prov, struct cs_card_data* card)
{
if (caid!=card->caid) return 0;
// Dont care about provider for caid non via/seca
if ( ((card->caid & 0xff00)!=0x0100) && ((card->caid & 0xff00)!=0x0500) ) return 1;
int i;
for(i=0; i<card->nbprov;i++) if (prov==card->prov[i]) return 1;
return 0;
}
// Search for a card with best sid val.
// TODO: option validecmtime-ecmtime
int sidata_getval(struct server_data *srv, struct cardserver_data *cs, uint16_t caid, uint32_t prov, uint16_t sid, struct cs_card_data **selcard )
{
struct cs_card_data *card = NULL;
*selcard = NULL;
if ( (srv->type==TYPE_NEWCAMD) || (srv->type==TYPE_RADEGAST) || (srv->type==TYPE_CAMD35) || (srv->type==TYPE_CS378X) ) {
card = srv->card;
while (card) {
if ( match_card(caid,prov,card) ) break;
card = card->next;
}
*selcard = card;
if (card) {
struct sid_data *sidata = card->sids[sid>>8];
while (sidata) {
if (sidata->sid==sid)
if (sidata->prov==prov) return sidata->val;
sidata = sidata->next;
}
}
return 0; // Channel not found in sid cache
}
#ifdef CCCAM_CLI
else if (srv->type==TYPE_CCCAM) {
// Search for availabe card cannot be found in sids
*selcard = NULL;
int selsidvalue = 0;
card = srv->card;
while (card) {
if ( match_card(caid,prov,card)
|| ( !prov && cs && cs_cmp_card(card, cs) ) // use for prov=0
) {
// Search fo sid
int sidvalue = 0; // by default
struct sid_data *sidata = card->sids[sid>>8];
while (sidata) {
if ( (sidata->sid==sid)&&(sidata->prov==prov) ) {
sidvalue = sidata->val;
break;
}
sidata = sidata->next;
}
// Check with Selected card (sidvalue) TODO: classify by ecmtime, decode, stability
if (*selcard) {
if ( selsidvalue<0 ) {
if (sidvalue>=0) { *selcard = card; selsidvalue = sidvalue; }
else if (card->uphops<(*selcard)->uphops) { *selcard = card; selsidvalue = sidvalue; }
}
else if ( selsidvalue==0 ) {
if (sidvalue>0) { *selcard = card; selsidvalue = sidvalue; }
else if (sidvalue==0) if (card->uphops<(*selcard)->uphops) { *selcard = card; selsidvalue = sidvalue; }
}
else if (sidvalue>0) if (card->uphops<(*selcard)->uphops) { *selcard = card; selsidvalue = sidvalue; }
}
else { *selcard = card; selsidvalue = sidvalue; }
}
card = card->next;
}
return selsidvalue;
}
#endif
return 0;
}
#define MAXSRVTAB 255
struct srvtab_data
{
struct server_data *srv;
struct cs_card_data *card; // selected card
uint32_t shareid; // Selected Card ShareID
int uphops;
int val; // sid value
unsigned int ecmtime; // Card Ecmtime
uint32_t ecmperhr;
};
struct srvtab_data srvlist[MAXSRVTAB];
struct srvtab_data *psrvlist[MAXSRVTAB];
struct srvtab_data *srvtemp;
int srvtab_arrange(struct cardserver_data *cs, ECM_DATA *ecm, int bestone )
{
int i,j;
int nbsrv = 0;
struct server_data *srv;
memset( srvlist, 0 , sizeof(srvlist) );
nbsrv = 0;
// MULTICARD Servers Selection (Newcamd,CCcam,Mgcamd...) ;)
unsigned int ticks = GetTickCount();
srv = cfg.server;
while ( srv && (nbsrv<MAXSRVTAB) ) {
if ( !IS_DISABLED(srv->flags)&&(srv->connection.status>0) )
if (
( cs->option.fallownewcamd && (srv->type==TYPE_NEWCAMD) )
|| ( cs->option.fallowcccam && (srv->type==TYPE_CCCAM) )
|| ( cs->option.fallowradegast && (srv->type==TYPE_RADEGAST) )
|| ( cs->option.fallowcamd35 && (srv->type==TYPE_CAMD35) )
|| ( cs->option.fallowcs378x && (srv->type==TYPE_CS378X) )
)
// Remove Circular request: check for client ip & srv ip
if ( (srv->host->ip==0x0100007F) || ( !ecm_checkip(ecm, srv->host->ip) && !ecm_checksrvip(ecm, srv->host->ip) ) )
{
// Check for CS PORTS
for(i=0; i<MAX_CSPORTS; i++ ) {
if (!srv->csport[i]) break;
if (srv->csport[i]==cs->newcamd.port) {
i=0;
break;
}
}
if (i==0) { // ADD TO PROFILE
//Check for used servers, dont reuse
for (i=0; i<20;i++) {
if (!ecm->server[i].srvid) break;
if (ecm->server[i].srvid==srv->id) break;
}
if ( (i>=20)||(ecm->server[i].srvid!=srv->id) ) {
// Check for ECM TIMEOUT
if ( (srv->busy)&&((srv->lastecmtime+9000)<ticks) ) { // timeout
debugf(getdbgflag(DBG_SERVER,0,srv->id)," ??? server (%s:%d) doesnt send ecm answer\n", srv->host->name,srv->port);
srv->ecmtimeout++;
srv->busy = 0;
disconnect_srv(srv);
}
else {
// Check for newcamd server sids
i = 0;
if ( srv->sids && (srv->type==TYPE_NEWCAMD) ) {
struct sid_chid_data *sid = srv->sids;
for(i=0; i<MAX_SIDS; i++,sid++) {
if ( sid->sid==0 ) break;
if (sid->sid==ecm->sid)
if (!sid->chid || (sid->chid==ecm->chid) ) { i=0; break; }
}
}
if (i==0) {
// check for any card to decode
pthread_mutex_lock(&srv->lock);
// best card to decode is selected, it may there is only worst one but is returned
struct cs_card_data *pcard = NULL;
int val = sidata_getval( srv, cs, ecm->caid, ecm->provid, ecm->sid, &pcard);
if ( !cs->option.maxfailedecm || (val > -cs->option.maxfailedecm) ) { // available card+sid : block card that have decode failed on sid
if (pcard) {
int ecmtime = 0;
if (srv->type==TYPE_CCCAM)
if (pcard->ecmok>10) ecmtime = pcard->ecmoktime/pcard->ecmok; else ecmtime = 0;
else
if (srv->ecmok>10) ecmtime = srv->ecmoktime/srv->ecmok; else ecmtime = 0;
if ( !cs->option.server.validecmtime || (ecmtime<cs->option.server.validecmtime) ) {
srvlist[nbsrv].srv = srv;
srvlist[nbsrv].card = pcard; // default card
srvlist[nbsrv].shareid = pcard->shareid; // default card
srvlist[nbsrv].uphops = pcard->uphops;
srvlist[nbsrv].val = val;
srvlist[nbsrv].ecmtime = ecmtime;
psrvlist[nbsrv] = &srvlist[nbsrv];
nbsrv++;
}
}
}
pthread_mutex_unlock(&srv->lock);
}
}
}
}
}
srv = srv->next;
}
//debugf(0, " A*srvtab_arrange(%04x:%06x:%04x) Servers = %d\n", ecm->caid, ecm->provid, ecm->sid, nbsrv);
//Remove Cardservers with delay time
if (cs->option.server.timeperecm) {
i=0;
for(j=0; j<nbsrv; j++) {
//if ( (psrvlist[j]->srv->host->ip!=0x0100007F)&&(psrvlist[j]->srv->type==TYPE_NEWCAMD) )
if ( (psrvlist[j]->srv->type==TYPE_NEWCAMD) ) {
unsigned int msperecm = ( (ticks-psrvlist[j]->srv->connection.time) + psrvlist[j]->srv->connection.uptime ) / (psrvlist[j]->srv->ecmnb+1);
unsigned int tim;
if ( msperecm > (2*cs->option.server.timeperecm) ) tim = 0;
else if ( msperecm > cs->option.server.timeperecm ) tim = (2*cs->option.server.timeperecm)-msperecm;
else tim = cs->option.server.timeperecm;
if ( (psrvlist[j]->srv->lastecmtime+tim)<=ticks ) {
if (i<j) psrvlist[i] = psrvlist[j];
i++;
}
}
else {
if (i<j) psrvlist[i] = psrvlist[j];
i++;
}
}
psrvlist[i] = NULL;
nbsrv = i;
}
//debugf(0, " B*srvtab_arrange(%04x:%06x:%04x) Servers = %d\n", ecm->caid, ecm->provid, ecm->sid, nbsrv);
// Store number of available servers, Runtime ADD SIDS
if (ecm->sid) {
for(i=0; i<1024; i++) {
if (cs->deniedsids[i].sid==ecm->sid) {
cs->deniedsids[i].nbsrv = nbsrv;
break;
}
if (!cs->deniedsids[i].sid) {
cs->deniedsids[i].sid = ecm->sid;
cs->deniedsids[i].nbsrv = nbsrv;
break;
}
}
}
// Check if there is no/few servers to decode, send decode failed to client
// dont get from few servers (for many cccam servers)
if (nbsrv<=cs->option.server.threshold) {
return -1;
}
// Remove Busy Servers
i=0;
for(j=0; j<nbsrv; j++) {
if (!psrvlist[j]->srv->busy) {
if (i<j) psrvlist[i] = psrvlist[j];
i++;
}
}
psrvlist[i] = NULL;
nbsrv = i;
//// ARRANGE
// Arrange by ECM LAST SENT TIME
for(i=0; i<nbsrv-1; i++)
for(j=i+1; j<nbsrv; j++)
if ( psrvlist[i]->srv->lastecmtime > psrvlist[j]->srv->lastecmtime ) {
srvtemp = psrvlist[i];
psrvlist[i] = psrvlist[j];
psrvlist[j] = srvtemp;
}
ticks=GetTickCount();
for(i=0; i<nbsrv; i++)
psrvlist[i]->ecmperhr = (psrvlist[i]->srv->ecmnb*3600*1000) / ( 1+ (ticks-psrvlist[i]->srv->connection.time)+psrvlist[i]->srv->connection.uptime );
if (!bestone)
// Arrange by ECM LAST SENT TIME && unbusy state & sid ok
for(i=0; i<nbsrv-1; i++)
for(j=i+1; j<nbsrv; j++) {
if ( (psrvlist[i]->val>=0)&&(psrvlist[i]->srv->priority > psrvlist[j]->srv->priority) ) continue;
if ( (psrvlist[j]->val>=0)&&(psrvlist[j]->srv->priority > psrvlist[i]->srv->priority) ) { // check if using local card
srvtemp = psrvlist[i];
psrvlist[i] = psrvlist[j];
psrvlist[j] = srvtemp;
}
else if (psrvlist[i]->val>=0) {
if (psrvlist[j]->val>=0) {
// Check for card uphops
if (psrvlist[i]->uphops > psrvlist[j]->uphops) {
srvtemp = psrvlist[i];
psrvlist[i] = psrvlist[j];
psrvlist[j] = srvtemp;
}
else if ( psrvlist[i]->ecmperhr > psrvlist[j]->ecmperhr ) {
srvtemp = psrvlist[i];
psrvlist[i] = psrvlist[j];
psrvlist[j] = srvtemp;
}
}
}
else if (psrvlist[i]->val==-1) {
if (psrvlist[j]->val>=0) {
srvtemp = psrvlist[i];
psrvlist[i] = psrvlist[j];
psrvlist[j] = srvtemp;
}
else if (psrvlist[j]->val==-1) {
if ( psrvlist[i]->ecmperhr > psrvlist[j]->ecmperhr ) {
srvtemp = psrvlist[i];
psrvlist[i] = psrvlist[j];
psrvlist[j] = srvtemp;
}
}
}
else {
if (psrvlist[j]->val>=-1) {
srvtemp = psrvlist[i];
psrvlist[i] = psrvlist[j];
psrvlist[j] = srvtemp;
}
else {
if ( psrvlist[i]->ecmperhr > psrvlist[j]->ecmperhr ) {
srvtemp = psrvlist[i];
psrvlist[i] = psrvlist[j];
psrvlist[j] = srvtemp;
}
}
}
}
else
for(i=0; i<nbsrv-1; i++)
for(j=i+1; j<nbsrv; j++) {
if ( (psrvlist[i]->val>0)&&(psrvlist[i]->srv->priority > psrvlist[j]->srv->priority) ) continue;
if (psrvlist[i]->val>0) {
if ( psrvlist[j]->srv->priority > psrvlist[i]->srv->priority ) {
srvtemp = psrvlist[i];
psrvlist[i] = psrvlist[j];
psrvlist[j] = srvtemp;
}
else if (psrvlist[j]->val>0) {
if ( ( psrvlist[i]->ecmperhr > psrvlist[j]->ecmperhr ) ) {
srvtemp = psrvlist[i];
psrvlist[i] = psrvlist[j];
psrvlist[j] = srvtemp;
}
}
}
else if (psrvlist[i]->val==0) {
if (psrvlist[j]->val>0) {
srvtemp = psrvlist[i];
psrvlist[i] = psrvlist[j];
psrvlist[j] = srvtemp;
}
else if (psrvlist[j]->val==0) {
if ( ( psrvlist[i]->ecmperhr > psrvlist[j]->ecmperhr ) ) {
srvtemp = psrvlist[i];
psrvlist[i] = psrvlist[j];
psrvlist[j] = srvtemp;
}
}
}
else {
if (psrvlist[j]->val>=0) {
srvtemp = psrvlist[i];
psrvlist[i] = psrvlist[j];
psrvlist[j] = srvtemp;
}
else {
if ( psrvlist[i]->val < psrvlist[j]->val ) {
srvtemp = psrvlist[i];
psrvlist[i] = psrvlist[j];
psrvlist[j] = srvtemp;
}
}
}
}
return nbsrv;
}