./ MultiCS.r82 / srv-radegast.c
///////////////////////////////////////////////////////////////////////////////
// PROTO
///////////////////////////////////////////////////////////////////////////////
void *rdgd_connect_cli_thread(void *param);
void rdgd_getclimsg();
uint rdgd_check_sendcw();
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void rdgd_senddcw_cli(struct rdgd_client_data *cli)
{
unsigned char buf[CWS_NETMSGSIZE];
if (cli->ecm.status==STAT_DCW_SENT) {
debugf(0, " +> cw send failed to radegast client (%s), cw already sent\n", ip2string(cli->ip));
return;
}
if (cli->handle==INVALID_SOCKET) {
debugf(0, " +> cw send failed to radegast client (%s), client disconnected\n", ip2string(cli->ip));
return;
}
if (!cli->ecm.busy) {
debugf(0, " +> cw send failed to radegast client (%s), no ecm request\n", ip2string(cli->ip));
return;
}
ECM_DATA *ecm = getecmbyid(cli->ecm.id);
if (ecm) {
cli->ecm.lastcaid = ecm->caid;
cli->ecm.lastprov = ecm->provid;
cli->ecm.lastsid = ecm->sid;
cli->ecm.lastdecodetime = GetTickCount()-cli->ecm.recvtime;
}
if ( ecm && (ecm->dcwstatus==STAT_DCW_SUCCESS) ) {
cli->ecm.lastdcwsrctype = ecm->dcwsrctype;
cli->ecm.lastdcwsrcid = ecm->dcwsrcid;
cli->ecm.laststatus=1;
cli->ecmok++;
cli->ecmoktime += GetTickCount()-cli->ecm.recvtime;
// Send DCW
buf[0] = 0x02;
buf[1] = 0x12;
buf[2] = 0x05;
buf[3] = 0x10;
memcpy( &buf[4], ecm->cw, 16 );
rdgd_message_send( cli->handle, buf, 0x14);
debugf(0, " => cw to client (%s) ch %04x:%06x:%04x (%dms)\n", ip2string(cli->ip), ecm->caid,ecm->provid,ecm->sid, GetTickCount()-cli->ecm.recvtime);
cli->lastdcwtime = GetTickCount();
}
else { //if (ecm->data->dcwstatus==STAT_DCW_FAILED)
cli->ecm.laststatus=0;
cli->ecm.lastdcwsrctype = DCW_SOURCE_NONE;
cli->ecm.lastdcwsrcid = 0;
buf[0] = 0x02;
buf[1] = 0x02;
buf[2] = 0x04;
buf[3] = 0x00;
rdgd_message_send( cli->handle, buf, 4);
debugf(0, " |> decode failed to client (%s) ch %04x:%06x:%04x (%dms)\n", ip2string(cli->ip), ecm->caid,ecm->provid,ecm->sid, GetTickCount()-cli->ecm.recvtime);
}
cli->ecm.busy=0;
cli->ecm.status = STAT_DCW_SENT;
}
///////////////////////////////////////////////////////////////////////////////
void rdgd_disconnect_cli(struct cardserver_data *cs,struct rdgd_client_data *cli)
{
if (cli)
if (cli->handle>0) {
//pthread_mutex_lock(&prg.lockrdgdcli);
debugf(0, " radegast: client (%s) disconnected\n", ip2string(cli->ip));
close(cli->handle);
// Remove
struct rdgd_client_data *n = cs->radegast.client;
if (n) {
if (n==cli) {
cs->radegast.client = n->next;
free(cli);
}
else {
while (n->next) {
if (cli==n->next) {
n->next = n->next->next;
free(cli);
break;
}
n = n->next;
}
}
}
//pthread_mutex_unlock(&prg.lockrdgdcli);
}
}
void *rdgd_connect_cli_thread(void *param)
{
int clientsock;
struct sockaddr_in clientaddr;
socklen_t socklen = sizeof(struct sockaddr);
while (1) {
pthread_mutex_lock(&prg.lockrdgdsrv);
struct pollfd pfd[MAX_CSPORTS];
int pfdcount = 0;
struct cardserver_data *cs = cfg.cardserver;
while(cs) {
if (cs->radegast.handle>0) {
cs->radegast.ipoll = pfdcount;
pfd[pfdcount].fd = cs->radegast.handle;
pfd[pfdcount++].events = POLLIN | POLLPRI;
} else cs->radegast.ipoll = -1;
cs = cs->next;
}
int retval = poll(pfd, pfdcount, 3013);
if (retval>0) {
struct cardserver_data *cs = cfg.cardserver;
while(cs) {
if ( (cs->radegast.handle>0) && (cs->radegast.ipoll>=0) && (cs->radegast.handle==pfd[cs->radegast.ipoll].fd) ) {
if ( pfd[cs->radegast.ipoll].revents & (POLLIN|POLLPRI) ) {
clientsock = accept(cs->radegast.handle, (struct sockaddr*)&clientaddr, &socklen );
if (clientsock<0) {
if (errno == EAGAIN || errno == EINTR) continue;
else {
debugf(0, " Radegast: Accept failed (errno=%d)\n",errno);
usleep(1000);
}
}
else {
SetSocketKeepalive(clientsock);
SetSocketNoDelay(clientsock);
SetSoketNonBlocking(clientsock);
// ADD TO DB
struct rdgd_client_data *cli = malloc( sizeof(struct rdgd_client_data) );
memset( cli, 0, sizeof(struct rdgd_client_data) );
cli->chkrecvtime = 0;
cli->handle = clientsock;
cli->ip = clientaddr.sin_addr.s_addr;
pthread_mutex_lock(&prg.lockrdgdcli);
cli->next = cs->radegast.client;
cs->radegast.client = cli;
debugf(0, " radegast: client (%s) connected\n", ip2string(cli->ip));
pthread_mutex_unlock(&prg.lockrdgdcli);
pipe_wakeup( prg.pipe.ecm[1] );
}
}
}
cs = cs->next;
}
}
pthread_mutex_unlock(&prg.lockrdgdsrv);
usleep(3000);
}
END_PROCESS = 1;
}
void rdgd_store_ecmclient(struct cardserver_data *cs, ECM_DATA *ecm, struct rdgd_client_data *cli)
{
cli->ecm.recvtime = GetTickCount();
cli->ecm.request = ecm;
cli->ecm.status = STAT_ECM_SENT;
ecm_addip(ecm, cli->ip);
}
int accept_ecm (struct cardserver_data *cs, uint16_t caid, uint32_t provid, uint16_t sid)
{
// Check for caid, accept caid=0
if ( !accept_caid(cs,caid) ) return 0;
// Check for provid, accept provid==0
if ( !accept_prov(cs,provid) ) return 0;
// Check for Accepted sids
if ( !accept_sid(cs,sid) ) return 0;
return 1;
}
void rdgd_cli_recvmsg(struct rdgd_client_data *cli, struct cardserver_data *cs)
{
int len;
unsigned char buf[300];
int i;
if (cli->handle>0) {
len = rdgd_check_message(cli->handle);
if (len==0) {
debugf(0, " radegast: client (%s) read failed %d\n", ip2string(cli->ip),len);
rdgd_disconnect_cli(cs,cli);
}
else if (len==-1) {
if (!cli->chkrecvtime) cli->chkrecvtime = GetTickCount();
else if ( (cli->chkrecvtime+300)<GetTickCount() ) {
debugf(0, " radegast: client (%s) read failed %d\n", ip2string(cli->ip),len);
rdgd_disconnect_cli(cs,cli);
}
}
else if (len>0) {
cli->chkrecvtime = 0;
len = rdgd_message_receive(cli->handle, buf, 0);
if (len==0) {
debugf(0, " radegast: client (%s) read failed %d\n", ip2string(cli->ip),len);
rdgd_disconnect_cli(cs,cli);
}
else if (len<0) {
debugf(0, " radegast: client '%s' read failed %d(%d)\n", ip2string(cli->ip),len,errno);
rdgd_disconnect_cli(cs,cli);
}
else if (len>0) switch ( buf[0] ) {
case 0x01: // ECM
cli->lastecmtime = GetTickCount();
cli->ecmnb++;
cli->ecm.id = -1; // ECM DENIED
if (cli->ecm.busy) {
cli->ecmdenied++;
rdgd_senddcw_cli(cli);
break;
}
uint16_t caid = 0;
uint32_t provid = 0;
unsigned char ecmdata[300];
memset(ecmdata, 0, sizeof(ecmdata));
int ecmlen=0;
int index = 2;
while (index<len) {
//entry = buf[index];
//len = buf[index+1];
switch (buf[index]) {
case 2: // CAID (upper byte only, oldstyle)
caid = buf[index+2]<<8;
break;
case 10: // CAID
caid = (buf[index+2]<<8) | buf[index+3];
break;
case 3: // ECM DATA
ecmlen = buf[index+1];
memcpy( ecmdata, &buf[index+2], ecmlen);
break;
case 6: // PROVID (ASCII)
for (i=0; i<buf[index+1]; i++) provid = (provid<<4) | hexvalue(buf[index+2+i]);
//provid = hex2int(char *src); // 6
break;
case 7: // KEYNR (ASCII), not needed
break;
case 8: // ECM PROCESS PID ?? don't know, not needed
break;
}
index += buf[index+1]+2;
}
if (!accept_ecm(cs,caid,provid,0)) {
rdgd_senddcw_cli(cli);
break;
}
// ACCEPTED
pthread_mutex_lock(&prg.lockecm); //###
// Search for ECM
int ecmid = search_ecmdata_dcw( ecmdata, ecmlen, 0); // dont get failed ecm request from cache
if ( ecmid!=-1 ) {
ECM_DATA *ecm=getecmbyid(ecmid);
ecm->lastrecvtime = GetTickCount();
//TODO: Add another card for sending ecm
rdgd_store_ecmclient(cs, ecmid, cli);
debugf(0, " <- ecm from client (%s) ch %04x:%06x:%04x*\n", ip2string(cli->ip), caid, provid, 0);
cli->ecm.busy=1;
cli->ecm.hash = ecm->hash;
}
else {
cs->ecmaccepted++;
// Setup ECM Request for Server(s)
ecmid = store_ecmdata(cs, ecmdata, ecmlen, 0, caid, provid);
ECM_DATA *ecm=getecmbyid(ecmid);
rdgd_store_ecmclient(cs, ecmid, cli);
debugf(0, " <- ecm from client (%s) ch %04x:%06x:%04x\n", ip2string(cli->ip), caid, provid, 0);
cli->ecm.busy=1;
cli->ecm.hash = ecm->hash;
if (cs->option.fallowcache && cfg.cache.peer) {
ecm->waitcache = 1;
ecm->dcwstatus = STAT_DCW_WAITCACHE;
ecm->checktime = ecm->recvtime + cs->option.cachetimeout;
pipe_cache_find(ecm, cs);
} else ecm->dcwstatus = STAT_DCW_WAIT;
}
pthread_mutex_unlock(&prg.lockecm); //###
wakeup_sendecm();
break;
default:
buf[0] = 0x81;
buf[1] = 0;
rdgd_message_send(cli->handle,buf,2);
//radegast_send(answer);
//cs_log("unknown request %02X, len=%d", buf[0], buf[1]);
}
}
}
}
// Check sending cw to clients
uint rdgd_check_sendcw()
{
struct cardserver_data *cs = cfg.cardserver;
uint restime = GetTickCount() + 10000;
uint clitime = 0;
while (cs) {
if (cs->radegast.handle>0) {
struct rdgd_client_data *cli = cs->radegast.client;
uint32_t ticks = GetTickCount();
while (cli) {
if ( (cli->handle>0)&&(cli->ecm.busy) ) {
clitime = ticks+11000;
// Check for DCW ANSWER
ECM_DATA *ecm = getecmbyid(cli->ecm.id);
if (ecm) {
// Check for FAILED
if (ecm->dcwstatus==STAT_DCW_FAILED) rdgd_senddcw_cli( cli );
// Check for SUCCESS
else if (ecm->dcwstatus==STAT_DCW_SUCCESS) rdgd_senddcw_cli( cli );
// check for timeout
else if ( (cli->ecm.recvtime+cs->option.dcw.timeout) < ticks ) rdgd_senddcw_cli( cli ); else clitime = cli->ecm.recvtime+cs->option.dcw.timeout;
}
else rdgd_senddcw_cli( cli ); // failed
if (restime>clitime) restime = clitime;
}
cli = cli->next;
}
}
cs = cs->next;
}
return (restime+1);
}