./ MultiCS.r82 / cli-cccam.c
struct cs_card_data *cc_getcardbyid( struct server_data *srv, uint32_t id );
int cc_sendecm_srv(struct server_data *srv, ECM_DATA *ecm);
///////////////////////////////////////////////////////////////////////////////
// CLIENT CONNECT
///////////////////////////////////////////////////////////////////////////////
struct cs_card_data *cc_getcardbyid( struct server_data *srv, uint32_t id )
{
struct cs_card_data *card = srv->card;
while (card) {
if (card->shareid==id) return card;
card = card->next;
}
return NULL;
}
// Send Client info to server.
int cc_sendinfo_srv(struct server_data *srv, int ismultics)
{
uint8_t buf[CC_MAXMSGSIZE];
memset(buf, 0, CC_MAXMSGSIZE);
memcpy(buf, srv->user, 20);
memcpy(buf + 20, cfg.cccam.nodeid, 8 );
buf[28] = 0; //srv->wantemus;
memcpy(buf + 29, cfg.cccam.version, 32); // cccam version (ascii)
if (ismultics) {
buf[57]='W'; buf[58]='H'; buf[59]='O';
}
memcpy(buf + 61, cfg.cccam.build, 32); // build number (ascii)
debugf( getdbgflag(DBG_SERVER, 0, srv->id), " Server: send client info User: '%s', Version: '%s', Build: '%s'.\n", srv->user, cfg.cccam.version, cfg.cccam.build);
return cc_msg_send( srv->handle, &srv->sendblock, CC_MSG_CLI_INFO, 20 + 8 + 1 + 64, buf);
}
///////////////////////////////////////////////////////////////////////////////
// Connect to a server.
// Return
// 0: no error
void *cacheex_cc_srv_recvmsg(struct server_data *srv);
static char CCcam[] = "CCcam";
static char CCcam_OScam[] = "CCcam/OScam";
static char CCcam_MultiCS[] = "CCcam/MCS";
int cc_connect_srv(struct server_data *srv, int fd)
{
int n;
uint8_t data[20];
uint8_t hash[SHA_DIGEST_LENGTH];
uint8_t buf[CC_MAXMSGSIZE];
char pwd[64];
//
if (fd < 0) return -1;
// INIT
srv->progname = CCcam;
memset( srv->version, 0, sizeof(srv->version) );
// get init seed(random) from server
if((n = recv_nonb(fd, data, 16,5000)) != 16) {
static char msg[]= "Server does not return init sequence";
srv->statmsg = msg;
debugf( getdbgflag(DBG_SERVER, 0, srv->id), " Server (%s:%d) does not return 16 bytes\n", srv->host->name,srv->port);
return -2;
}
#ifdef DEBUG_NETWORK
if (flag_debugnet) {
debugf( getdbgflag(DBG_SERVER, 0, srv->id), " CCcam: receive server init seed (%d)\n",n);
debughex(data,n);
}
#endif
// Check Multics
int ismultics = 0;
uint8_t a = (data[0]^'M') + data[1] + data[2];
uint8_t b = data[4] + (data[5]^'C') + data[6];
uint8_t c = data[8] + data[9] + (data[10]^'S');
if ( (a==data[3])&&(b==data[7])&&(c==data[11]) ) {
srv->progname = CCcam_MultiCS;
ismultics = 1;
}
//Check oscam-cccam
uint32_t sum = 0x1234;
uint32_t recv_sum = (data[14] << 8) | data[15];
int i;
for (i=0; i<14; i++) sum+= data[i];
if (sum==recv_sum) srv->progname = CCcam_OScam;
cc_crypt_xor(data); // XOR init bytes with 'CCcam'
SHA_CTX ctx;
SHA1_Init(&ctx);
SHA1_Update(&ctx, data, 16);
SHA1_Final(hash, &ctx);
//debugdump(hash, sizeof(hash), "CCcam: sha1 hash:");
//init crypto states
cc_crypt_init(&srv->recvblock, hash, 20);
cc_decrypt(&srv->recvblock, data, 16);
cc_crypt_init(&srv->sendblock, data, 16);
cc_decrypt(&srv->sendblock, hash, 20);
if ( !cc_msg_send( fd, &srv->sendblock, CC_MSG_NO_HEADER, 20,hash) ) return -1; // send crypted hash to server
memset(buf, 0, sizeof(buf));
memcpy(buf, srv->user, 20);
//debugf( getdbgflag(DBG_SERVER, 0, srv->id), " CCcam: username '%s'\n",srv->username);
if ( !cc_msg_send( fd, &srv->sendblock, CC_MSG_NO_HEADER, 20, buf) ) return -1; // send usr '0' padded -> 20 bytes
memset(buf, 0, sizeof(buf));
memset(pwd, 0, sizeof(pwd));
//debugf("CCcam: 'CCcam' xor\n");
memcpy(buf, "CCcam\0", 6);
strncpy(pwd, srv->pass, 63);
cc_encrypt(&srv->sendblock, (uint8_t *)pwd, strlen(pwd));
if ( !cc_msg_send( fd, &srv->sendblock, CC_MSG_NO_HEADER, 6, buf) ) return -1; // send 'CCcam' xor w/ pwd
if ((n = recv_nonb(fd, data, 20,5000)) != 20) {
static char msg[]= "Password ACK not received";
srv->statmsg = msg;
debugf( getdbgflag(DBG_SERVER, 0, srv->id), " CCcam: login failed to Server (%s:%d), pwd ack not received (n = %d)\n",srv->host->name,srv->port, n);
return -2;
}
cc_decrypt(&srv->recvblock, data, 20);
//hexdump(data, 20, "CCcam: pwd ack received:");
if (memcmp(data, buf, 5)) { // check server response
static char msg[]= "Invalid user/pass";
srv->statmsg = msg;
debugf( getdbgflag(DBG_SERVER, 0, srv->id), " CCcam: login failed to Server (%s:%d), usr/pwd invalid\n",srv->host->name,srv->port);
return -2;
}// else debugf( getdbgflag(DBG_SERVER, 0, srv->id), " CCcam: login succeeded to Server (%s:%d)\n",srv->host->name,srv->port);
srv->handle = fd;
if (!cc_sendinfo_srv(srv,ismultics)) {
srv->handle = -1;
static char msg[]= "Error sending client data";
srv->statmsg = msg;
debugf( getdbgflag(DBG_SERVER, 0, srv->id), " CCcam: login failed to Server (%s:%d), could not send client data\n",srv->host->name,srv->port);
return -3;
}
// Update Server data
static char msg[]= "Connected";
srv->statmsg = msg;
srv->connection.status = 1;
srv->connection.time = GetTickCount();
srv->keepalive.status = 0;
srv->keepalive.time = GetTickCount();
srv->busy = 0;
srv->lastecmoktime = 0;
srv->lastecmtime = 0;
srv->lastdcwtime = 0;
srv->chkrecvtime = 0;
srv->msg.len = 0;
//srv->handle = fd;
memset(srv->version,0,32);
#ifdef CACHEEX
if (srv->cacheex_mode==2) {
if (!create_thread( &srv->tid, (threadfn)cacheex_cc_srv_recvmsg, srv )) {
disconnect_srv(srv);
}
}
else
#endif
#ifdef EPOLL_ECM
pipe_pointer( prg.pipe.ecm[1], PIPE_SRV_CONNECTED, srv );
#else
pipe_cmd( prg.pipe.ecm[1], PIPE_SRV_CONNECTED );
#endif
return 0;
}
///////////////////////////////////////////////////////////////////////////////
void cc_srv_recvmsg(struct server_data *srv)
{
unsigned char buf[CC_MAXMSGSIZE];
struct cs_card_data *card;
struct cardserver_data *cs;
int i, len;
ECM_DATA *ecm;
if ( (srv->type==TYPE_CCCAM)&&(srv->handle>0) ) {
len = cc_peekmsg( srv->handle, &srv->recvblock, &srv->msg, buf );
if (len==0) {
debugf( getdbgflag(DBG_SERVER, 0, srv->id), " CCcam: server (%s:%d) read failed %d\n", srv->host->name, srv->port, len);
disconnect_srv(srv);
}
else if (len==-1) {
if (!srv->chkrecvtime) srv->chkrecvtime = GetTickCount();
else if ( (srv->chkrecvtime+500)<GetTickCount() ) {
debugf( getdbgflag(DBG_SERVER, 0, srv->id), " CCcam: server (%s:%d) read failed %d\n", srv->host->name, srv->port, len);
disconnect_srv(srv);
}
}
else if (len>0) {
srv->chkrecvtime = 0;
switch (buf[1]) {
case CC_MSG_CLI_INFO:
debugf( getdbgflag(DBG_SERVER, 0, srv->id), " CCcam: Client data ACK from Server (%s:%d)\n", srv->host->name,srv->port);
break;
case CC_MSG_ECM_REQUEST: // Get CW
if (!srv->busy) {
debugf( getdbgflag(DBG_SERVER, 0, srv->id), " [!] dcw error from server (%s:%d), unknown ecm request\n",srv->host->name,srv->port);
break;
}
#ifdef CACHEEX
if (srv->cacheex_mode) {
debugf( getdbgflag(DBG_SERVER, 0, srv->id), " [!] dcw error from cacheex server (%s:%d)\n",srv->host->name,srv->port);
break;
}
#endif
uint8_t dcw[16];
cc_crypt_cw( cfg.cccam.nodeid, srv->busycardid, &buf[4]);
memcpy(dcw, &buf[4], 16);
cc_decrypt(&srv->recvblock, buf+4, len-4); // additional crypto step
srv->busy = 0;
pipe_cmd( prg.pipe.ecm[1], PIPE_SRV_AVAILABLE );
srv->lastdcwtime = GetTickCount();
pthread_mutex_lock(&prg.lockecm); //###
ecm = srv->ecm.request;
if (!ecm) {
debugf( getdbgflag(DBG_SERVER, 0, srv->id), " [!] error cw from server (%s:%d), ecm not found!!!\n",srv->host->name,srv->port);
pthread_mutex_unlock(&prg.lockecm); //###
srv->busy = 0;
break;
}
// check for ECM???
if (ecm->hash!=srv->ecm.hash) {
debugf( getdbgflag(DBG_SERVER, 0, srv->id), " [!] error cw from server (%s:%d), ecm deleted!!!\n",srv->host->name,srv->port);
pthread_mutex_unlock(&prg.lockecm); //###
srv->busy = 0;
break;
}
cs = ecm->cs;
card = cc_getcardbyid( srv, srv->busycardid );
// Check for DCW
if (!acceptDCW(dcw)) {
srv->ecmerrdcw ++;
#ifdef SID_FILTER
if (cs && card) {
cardsids_update( card, ecm->provid, ecm->sid, -1);
srv_cstatadd( srv, cs->id, 0 , 0);
}
#endif
ecm_setsrvflag(srv->ecm.request, srv->id, ECM_SRV_REPLY_FAIL);
pthread_mutex_unlock(&prg.lockecm); //###
break;
}
// else {
srv->lastecmoktime = GetTickCount()-srv->lastecmtime;
srv->ecmoktime += srv->lastecmoktime;
srv->ecmok++;
ecm_setsrvflagdcw(srv->ecm.request, srv->id, ECM_SRV_REPLY_GOOD,dcw);
#ifdef SID_FILTER
if (cs && card) {
cardsids_update( card, ecm->provid, ecm->sid, 1); /// + Card nodeID
srv_cstatadd( srv, cs->id, 1 , srv->lastecmoktime);
}
#endif
if (card) {
card->ecmoktime += GetTickCount()-srv->lastecmtime;
card->ecmok++;
}
if (ecm->dcwstatus!=STAT_DCW_SUCCESS) {
static char msg[] = "Good dcw from CCcam server";
ecm->statusmsg = msg;
debugf( getdbgflagpro(DBG_SERVER, 0, srv->id,cs->id), " <= cw from CCcam server (%s:%d) ch %04x:%06x:%04x (%dms)\n", srv->host->name,srv->port, ecm->caid,ecm->provid,ecm->sid, GetTickCount()-srv->lastecmtime);
ecm_setdcw( ecm, dcw, DCW_SOURCE_SERVER, srv->id );
}
pthread_mutex_unlock(&prg.lockecm); //###
wakeup_sendecm(); // Wakeup ecm waiting for availabe servers
break;
case CC_MSG_ECM_NOK1: // EAGAIN, Retry
/*
if (!srv->busy) break;
ecm = srv->busyecm;
debugf( getdbgflag(DBG_SERVER, 0, srv->id), " <| decode1 failed from CCcam server (%s:%d) ch %04x:%06x:%04x (%dms)\n", srv->host->name,srv->port, ecm->caid,ecm->provid,ecm->sid, GetTickCount()-srv->lastecmtime);
if ( (GetTickCount()-srv->lastecmtime)<CC_ECMRETRY_TIMEOUT ) {
if (srv->retry<CC_ECMRETRY_MAX) {
srv->busy = 0;
if (cc_sendecm_srv(srv, ecm)) {
srv->lastecmtime = GetTickCount();
srv->busy = 1;
srv->retry++;
break;
}
}
}
if (srv->retry>=CC_ECMRETRY_MAX) {
ecm_setsrvflag(ecm, srv->id, ECM_SRV_EXCLUDE);
}
srv->busy = 0;
break;
*/
case CC_MSG_ECM_NOK2: // ecm decode failed
if (!srv->busy) {
debugf( getdbgflag(DBG_SERVER, 0, srv->id), " [!] dcw error from server (%s:%d), unknown ecm request\n",srv->host->name,srv->port);
break;
}
#ifdef CACHEEX
if (srv->cacheex_mode) {
debugf( getdbgflag(DBG_SERVER, 0, srv->id), " [!] dcw error from cacheex server (%s:%d)\n",srv->host->name,srv->port);
break;
}
#endif
pthread_mutex_lock(&prg.lockecm); //###
ecm = srv->ecm.request;
if (!ecm) {
debugf( getdbgflag(DBG_SERVER, 0, srv->id), " [!] dcw error from server (%s:%d), ecm not found!!!\n",srv->host->name,srv->port);
pthread_mutex_unlock(&prg.lockecm); //###
srv->busy = 0;
break;
}
// check for ECM???
if (ecm->hash!=srv->ecm.hash) {
debugf( getdbgflag(DBG_SERVER, 0, srv->id), " [!] dcw error from server (%s:%d), ecm deleted!!!\n",srv->host->name,srv->port);
pthread_mutex_unlock(&prg.lockecm); //###
srv->busy = 0;
break;
}
debugf( getdbgflagpro(DBG_SERVER, 0, srv->id,ecm->cs->id), " <| decode failed from CCcam server (%s:%d) ch %04x:%06x:%04x (%dms)\n", srv->host->name,srv->port, ecm->caid,ecm->provid,ecm->sid, GetTickCount()-srv->lastecmtime);
cs = ecm->cs;
if ( cs && (ecm->dcwstatus!=STAT_DCW_SUCCESS) && (srv->retry<cs->option.retry.cccam) ) {
if ((GetTickCount()-ecm->recvtime) < (cs->option.server.timeout*ecm->period)) {
srv->busy = 0;
if (cc_sendecm_srv(srv, ecm)) {
srv->lastecmtime = GetTickCount();
srv->busy = 1;
srv->retry++;
debugf( getdbgflagpro(DBG_SERVER, 0, srv->id,ecm->cs->id), " (RE%d) -> ecm to CCcam server (%s:%d) ch %04x:%06x:%04x\n",srv->retry,srv->host->name,srv->port,ecm->caid,ecm->provid,ecm->sid);
pthread_mutex_unlock(&prg.lockecm); //###
break;
}
}
}
#ifdef SID_FILTER
if (cs) {
card = cc_getcardbyid( srv, srv->busycardid );
if (card) cardsids_update(card, ecm->provid, ecm->sid, -1);
srv_cstatadd( srv, cs->id, 0 , 0);
}
#endif
ecm_setsrvflag(srv->ecm.request, srv->id, ECM_SRV_REPLY_FAIL);
srv->busy = 0;
pthread_mutex_unlock(&prg.lockecm); //###
pipe_cmd( prg.pipe.ecm[1], PIPE_SRV_AVAILABLE );
break;
case CC_MSG_BAD_ECM:
if ( !cc_msg_send( srv->handle, &srv->sendblock, CC_MSG_BAD_ECM, 0, NULL) ) disconnect_srv(srv);
//debugf( getdbgflag(DBG_SERVER, 0, srv->id), " CCcam: cmd 0x05 from Server (%s:%d)\n",srv->host->name,srv->port);
//currentecm.state = ECM_STATUS_FAILED;
break;
case CC_MSG_KEEPALIVE:
srv->keepalive.status = 0;
//debugf( getdbgflag(DBG_SERVER, 0, srv->id), " CCcam: Keepalive ACK from Server (%s:%d)\n",srv->host->name,srv->port);
break;
case CC_MSG_CARD_DEL: // Delete Card
pthread_mutex_lock(&prg.lockecm); //###
card = srv->card;
uint32_t k = buf[4]<<24 | buf[5]<<16 | buf[6]<<8 | buf[7];
struct cs_card_data *prevcard = NULL;
while (card) {
if (card->shareid==k) {
debugf( getdbgflag(DBG_SERVER, 0, srv->id), " CCcam: server (%s:%d), remove share-id %d\n",srv->host->name,srv->port,k);
if (prevcard) prevcard->next = card->next; else srv->card = card->next;
//Free SIDs
int s;
for(s=0; s<256; s++) {
struct sid_data *sid1 = card->sids[s];
while (sid1) {
struct sid_data *sid = sid1;
sid1 = sid1->next;
free(sid);
}
}
free(card);
// check for current ecm
if (srv->busy && (srv->busycardid==k) ) ecm_setsrvflag(srv->ecm.request, srv->id, ECM_SRV_EXCLUDE);
break;
}
prevcard = card;
card = card->next;
}
pthread_mutex_unlock(&prg.lockecm); //###
break;
case CC_MSG_CARD_ADD:
// remove own cards -> same nodeid "cfg.cccam.nodeid"
if ( (buf[24]<=16) ) { // && memcmp(buf+26+buf[24]*7,cfg.cccam.nodeid,8) ) { // check Only the first 4 bytes
// nodeid index = 26 + 7 * buf[24]
struct cs_card_data tcard;
memset(&tcard, 0, sizeof(struct cs_card_data) );
tcard.shareid = buf[4]<<24 | buf[5]<<16 | buf[6]<<8 | buf[7];
tcard.uphops = buf[14]+1;
memcpy( tcard.nodeid, buf+26+buf[24]*7, 8);
tcard.caid = (buf[12]<<8)+(buf[13]);
tcard.nbprov = buf[24];
i = 26+buf[24]*7;
if (tcard.nbprov>CARD_MAXPROV) tcard.nbprov = CARD_MAXPROV;
debugf( getdbgflag(DBG_SERVER, 0, srv->id), " CCcam: new card (%s:%d) %02x%02x%02x%02x%02x%02x%02x%02x_%x uphops %d caid %04x providers %d\n",srv->host->name,srv->port, buf[i],buf[i+1],buf[i+2],buf[i+3],buf[i+4],buf[i+5],buf[i+6],buf[i+7],tcard.shareid ,tcard.uphops, tcard.caid, tcard.nbprov);
int nbprov = 0; // Accepted Providers
for (i=0;i<tcard.nbprov; i++) {
uint32_t provid = (buf[25+i*7]<<16) | (buf[26+i*7]<<8) | (buf[27+i*7]);
if ( tcard.uphops <= srv_sharelimits( srv, tcard.caid, provid) ) {
tcard.prov[nbprov] = provid;
nbprov++;
//debugf( getdbgflag(DBG_SERVER, 0, srv->id), " Accepted %04x:%06x\n", tcard.caid, provid);
}
//else debugf( getdbgflag(DBG_SERVER, 0, srv->id), " Ignored %04x:%06x\n", tcard.caid, provid);
}
if (nbprov) {
tcard.nbprov = nbprov;
//debugf( getdbgflag(DBG_SERVER, 0, srv->id), " CCcam: new card (%s:%d) %02x%02x%02x%02x%02x%02x%02x%02x_%x uphops %d caid %04x providers %d\n",srv->host->name,srv->port, buf[i],buf[i+1],buf[i+2],buf[i+3],buf[i+4],buf[i+5],buf[i+6],buf[i+7],tcard.shareid ,tcard.uphops, tcard.caid, tcard.nbprov);
card = malloc( sizeof(struct cs_card_data) );
memcpy( card, &tcard, sizeof(struct cs_card_data) );
pthread_mutex_lock(&prg.lockecm); //###
card->next = srv->card;
srv->card = card;
pthread_mutex_unlock(&prg.lockecm); //###
}
}
break;
case CC_MSG_SRV_INFO:
memcpy(srv->nodeid, buf+4, 8);
memcpy(srv->version, buf+12, 31);
if ( (srv->version[25]=='M')&&(srv->version[26]=='C')&&(srv->version[27]=='S')&&(srv->version[28]==0) ) {
sprintf( srv->version, "r%d", srv->version[29] | (srv->version[30]<<8));
srv->progname = CCcam_MultiCS;
// printf(" Multics %d\n", srv->version[29] | (srv->version[30]<<8) );
}
for (i=12; i<53; i++) {
if (!buf[i]) break;
if ( (buf[i]<32)||(buf[i]>'z') ) {
memset(srv->version, 0, 31);
break;
}
}
memcpy(srv->build, buf+44, 31);
debugf( getdbgflag(DBG_SERVER, 0, srv->id), " CCcam: server (%s:%d), info: version %s build %s\n",srv->host->name,srv->port,buf+12, buf+44);
break;
#ifdef CACHEEX
case CC_MSG_CACHE_PUSH:
if (srv->cacheex_mode!=2) break;
if (buf[18]==0) { // Got CW
if (acceptDCW(buf+44)) { // check for length also
uint8_t cw[16];
srv->cacheex.got[0]++;
int uphop = buf[60];
if (uphop<10) srv->cacheex.got[uphop]++;
struct cache_data cacheex;
cacheex.caid = (buf[4]<<8) | buf[5];
cacheex.provid = (buf[6]<<24) | (buf[7]<<16) | (buf[8]<<8) | buf[9];
cacheex.sid = (buf[14]<<8) | buf[15];
// Look for cardserver
cs = getcsbycaprovid(cacheex.caid, cacheex.provid);
if ( !cs || !cs->option.fallowcacheex ) {
srv->cacheex.badcw++;
break;
}
if ((buf[19+4]&0xFE)==0x80) cacheex.tag = buf[19+4]; else cacheex.tag = 0;
memcpy( cacheex.ecmd5, buf+24, 16);
if ( !checkECMD5(cacheex.ecmd5) ) srv->cacheex.csp++;
cacheex.hash = (buf[43]<<24) | (buf[42]<<16) | (buf[41]<<8) | buf[40];
memcpy( cw, buf+44, 16);
if (!cacheex_check(&cacheex)) break;
pthread_mutex_lock( &prg.lockcache );
int res = cache_setdcw( &cacheex, cw, NO_CYCLE, PEER_CACHEEX_SERVER | srv->id );
pthread_mutex_unlock( &prg.lockcache );
if (res&DCW_ERROR) {
if ( !(res&DCW_SKIP) ) srv->cacheex.badcw++;
}
else if (res&DCW_CYCLE) {
if ( cs->option.cacheex.maxhop>uphop ) {
uint8_t nodeid[8];
memcpy( nodeid, buf+61, 8);
pipe_send_cacheex_push_cache(&cacheex, cw, srv->nodeid); //cacheex_push(&cacheex, cw, nodeid);
}
}
//debugf( getdbgflag(DBG_CACHEEX, 0, 0)," CACHEEX PUSH from CCcam server (%s:%d) %04x:%06x:%04x:%08x\n", srv->host->name, srv->port,cacheex.caid,cacheex.provid,cacheex.sid,cacheex.hash);
}
}
/*
else {
cli->cacheex.totalreq++;
}
*/
break;
#endif
//default: debugdump(buf,len," CCcam: unknown packet from server (%s:%d): ",srv->host->name,srv->port);
} // switch
srv->keepalive.time = GetTickCount();
}
}
}
// Receive messages from server
// CACHEEX MODE 2
void *cacheex_cc_srv_recvmsg(struct server_data *srv)
{
srv->pid = syscall(SYS_gettid);
while (srv->handle>0) {
struct pollfd pfd;
pfd.fd = srv->handle;
pfd.events = POLLIN | POLLPRI;
int retval = poll(&pfd, 1, 3005); // for 3seconds
if (retval==0) continue;
else if (retval<0) { // error
disconnect_srv(srv);
break;
}
else if ( pfd.revents & (POLLIN|POLLPRI) ) cc_srv_recvmsg(srv);
else {
disconnect_srv(srv);
break;
}
}
srv->pid = 0;
return NULL;
}
///////////////////////////////////////////////////////////////////////////////
int cc_sendecm_srv(struct server_data *srv, ECM_DATA *ecm)
{
unsigned char buf[CC_MAXMSGSIZE];
//if ( (srv->handle>0)&&(!srv->busy) ) {
// if (!cc_getcardbyid(srv, srv->busycardid)) return 0;
//debugf( getdbgflag(DBG_SERVER, 0, srv->id), " -> ecm to CCcam server (%s:%d) ch %04x:%06x:%04x shareid %x\n", srv->host->name, srv->port,ecm->caid,ecm->provid,ecm->sid,srv->busycardid);
buf[0] = ecm->caid>>8;
buf[1] = ecm->caid&0xff;
buf[2] = ecm->provid>>24;
buf[3] = ecm->provid>>16;
buf[4] = ecm->provid>>8;
buf[5] = ecm->provid&0xff;
// srv->busycardid is saved from srvtab_arrange()
buf[6] = srv->busycardid>>24;
buf[7] = srv->busycardid>>16;
buf[8] = srv->busycardid>>8;
buf[9] = srv->busycardid&0xff;
buf[10] = ecm->sid>>8;
buf[11] = ecm->sid&0xff;
buf[12] = ecm->ecmlen;
memcpy( &buf[13],&ecm->ecm[0], ecm->ecmlen);
srv->lastecmtime = GetTickCount();
srv->busy = 1;
////srv->ecm.msgid = ecm->id;
return cc_msg_send( srv->handle, &srv->sendblock, CC_MSG_ECM_REQUEST, 13+ecm->ecmlen, buf );
//}
//return 0;
}