./ MultiCS.r82 / cli-cs378x.c
/////////////////////////////////////////////////////////////////////////////// // TCP /////////////////////////////////////////////////////////////////////////////// //CMD00 - ECM (request) //CMD01 - ECM (response) //CMD02 - EMM (in clientmode - set EMM, in server mode - EMM data) - obsolete //CMD03 - ECM (cascading request) //CMD04 - ECM (cascading response) //CMD05 - EMM (emm request) send cardata/cardinfo to client //CMD06 - EMM (incomming EMM in server mode) //CMD19 - EMM (incomming EMM in server mode) only seen with caid 0x1830 //CMD08 - Stop sending requests to the server for current srvid,prvid,caid //CMD44 - MPCS/OScam internal error notification //CMD55 - connect_on_init/keepalive //CMD0x3d - CACHEEX Cache-push id request //CMD0x3e - CACHEEX Cache-push id answer //CMD0x3f - CACHEEX cache-push void cs378x_send_keepalive(struct server_data *srv) { uint8_t buf[64]; #ifdef CACHEEX if (srv->cacheex_mode) { // Request Nodeid memset(buf, 0, 32); buf[0] = CAMD_CEX_IDREQUEST; buf[1] = 12; memcpy( buf+20, cccam_nodeid, 8); cs378x_send( srv->handle, &srv->encryptkey, srv->ucrc, buf, 20+12); } else #endif { // keepalive uint8_t buf[64]; memset(buf,0, 21); buf[0] = CAMD_KEEPALIVE; buf[1] = 1; buf[2] = 0; cs378x_send( srv->handle, &srv->encryptkey, srv->ucrc, buf, 20+1); } } /////////////////////////////////////////////////////////////////////////////// // SEND ECM /////////////////////////////////////////////////////////////////////////////// int cs378x_sendecm_srv(struct server_data *srv, ECM_DATA *ecm) { srv->lastecmtime = GetTickCount(); srv->ecmnb++; srv->busy=1; srv->ecm.msgid++; if (srv->ecm.msgid>0xfff) srv->ecm.msgid = 1; srv->ecm.request = ecm; unsigned char buf[1024]; memset(buf, 0, 20); buf[0] = 0; // Command buf[1] = 0; // Length buf[8] = ecm->sid>>8; buf[9] = ecm->sid&0xff; buf[10] = ecm->caid>>8; buf[11] = ecm->caid&0xff; buf[12] = ecm->provid>>24; buf[13] = ecm->provid>>16; buf[14] = ecm->provid>>8; buf[15] = ecm->provid&0xff; buf[16] = srv->ecm.msgid>>8; buf[17] = srv->ecm.msgid; memcpy( buf+20, ecm->ecm, ecm->ecmlen); cs378x_send( srv->handle, &srv->encryptkey, srv->ucrc, buf, 20+ecm->ecmlen); return 1; } /////////////////////////////////////////////////////////////////////////////// // RECV MSG /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // RECV MSG /////////////////////////////////////////////////////////////////////////////// // CACHEEX MODE 2 void *cs378x_srv_recvmsg(struct server_data *srv) { uint8_t cw[16]; struct cardserver_data *cs; /* // TEST KEEPALIVE uint32_t ticks = GetTickCount(); if ( !srv->keepalive.status && ((srv->keepalive.time+30000)<ticks) ) { cs378x_send_keepalive(srv); srv->keepalive.status = 1; // Sent and waiting for reply srv->keepalive.time = ticks; } else if ( (srv->keepalive.status==1) && ((srv->keepalive.time+5000)<ticks) ) { cs378x_send_keepalive(srv); srv->keepalive.status = 2; } else if ( (srv->keepalive.status>1) && ((srv->keepalive.time+10000)<ticks) ) { debugf(getdbgflag(DBG_SERVER,0,srv->id),, " cs378x server disconnected, keepalive timeout\n"); close(srv->handle); srv->handle = -1; srv->pid = 0; srv->connected = 0; srv->keepalive.status = 0; srv->keepalive.time = 0; return NULL; } */ unsigned char buf[2048]; int received = recv_nonb( srv->handle, buf, 32+4, 1000); if (received<=0) { disconnect_srv(srv); //debugf(getdbgflag(DBG_SERVER,0,srv->id), " cs378x server disconnected, receive timeout\n"); return NULL; } uint32_t ucrc = (buf[0]<<24)|(buf[1]<<16)|(buf[2]<<8)|buf[3]; if (srv->ucrc!=ucrc) { disconnect_srv(srv); //debugf(getdbgflag(DBG_SERVER,0,srv->id), " cs378x server disconnected, wrong ucrc\n"); return NULL; } aes_decrypt( &srv->decryptkey, buf+4, received-4); //Fix for ECM request size > 255 (use ecm length field) int datalen = buf[5]; if (buf[4] == 0) { datalen = (((buf[25] & 0x0f) << 8) | buf[26]) + 3; } else if ( (buf[4]&0xFC)==0x3C ) datalen = buf[5] | (buf[6] << 8); // cacheex int newlen = 4+camd35_padding(20+datalen); if (received<newlen) { int n = recv_nonb( srv->handle, buf+received, newlen-received, 500); if ( n != (newlen-received) ) { disconnect_srv(srv); //debugf(getdbgflag(DBG_SERVER,0,srv->id), " cs378x server disconnected, receive timeout\n"); return NULL; } aes_decrypt( &srv->decryptkey, buf+received, n); } //debugf(getdbgflag(DBG_SERVER,0,srv->id)," msg from cs378x server (%s:%d)\n", srv->host->name, srv->port); debughex(buf, newlen); switch (buf[4]) { case CAMD_ECM_REPLY: srv->lastdcwtime = GetTickCount(); if (!srv->busy) { debugf(getdbgflag(DBG_SERVER,0,srv->id)," [!] dcw error from cs378x server (%s:%d), unknown ecm request\n",srv->host->name,srv->port); break; } // if (buf[5]!=0x10) { debugf(getdbgflag(DBG_SERVER,0,srv->id)," [!] dcw error from cs378x server (%s:%d), wrong length!!!\n",srv->host->name,srv->port); break; } // Check for DCW if (!acceptDCW( buf+24 ) ) { srv->ecmerrdcw++; debugf(getdbgflag(DBG_SERVER,0,srv->id)," [!] dcw error from cs378x server (%s:%d), bad dcw!!!\n",srv->host->name,srv->port); break; } // Checl Stored ECM ECM_DATA *ecm = srv->ecm.request; if (!ecm) { debugf(getdbgflag(DBG_SERVER,0,srv->id)," [!] dcw error from cs378x server (%s:%d), ecm not found!!!\n",srv->host->name,srv->port); break; } // srv->busy = 0; pipe_cmd( prg.pipe.ecm[1], PIPE_SRV_AVAILABLE ); pthread_mutex_lock(&prg.lockecm); //### // check for ECM validity if (ecm->hash!=srv->ecm.hash) { debugf(getdbgflag(DBG_SERVER,0,srv->id)," [!] dcw error from cs378x server (%s:%d), ecm deleted!!!\n",srv->host->name,srv->port); pthread_mutex_unlock(&prg.lockecm); break; } srv->ecmok++; srv->lastecmoktime = GetTickCount()-srv->lastecmtime; srv->ecmoktime += srv->lastecmoktime; ecm_setsrvflagdcw( ecm, srv->id, ECM_SRV_REPLY_GOOD, buf+24 ); debugf(getdbgflagpro(DBG_SERVER,0,srv->id,ecm->cs->id)," <= cw from cs378x server (%s:%d) ch %04x:%06x:%04x (%dms)\n", srv->host->name,srv->port, ecm->caid,ecm->provid,ecm->sid, GetTickCount()-srv->lastecmtime); if (ecm->dcwstatus!=STAT_DCW_SUCCESS) { static char msg[] = "Good dcw from camd35 server"; ecm->statusmsg = msg; // Store ECM Answer ecm_setdcw( ecm, buf+24, DCW_SOURCE_SERVER, srv->id ); } else { //TODO: check same dcw between cards srv->ecmerrdcw ++; if ( memcmp( ecm->cw, buf+24, 16) ) debugf(getdbgflagpro(DBG_SERVER,0,srv->id,ecm->cs->id)," !!! different dcw from cs378x server (%s:%d)\n",srv->host->name,srv->port); } #ifdef SID_FILTER // ADD IN SID LIST cs= ecm->cs; if (cs) { cardsids_update( srv->busycard, ecm->provid, ecm->sid, 1); srv_cstatadd( srv, cs->id, 1 , srv->lastecmoktime); } #endif pthread_mutex_unlock(&prg.lockecm); //### break; case 0x44: srv->lastdcwtime = GetTickCount(); if (!srv->busy) { debugf(getdbgflag(DBG_SERVER,0,srv->id)," [!] dcw error from cs378x server (%s:%d), unknown ecm request\n",srv->host->name,srv->port); break; } // Checl Stored ECM ecm = srv->ecm.request; if (!ecm) { debugf(getdbgflag(DBG_SERVER,0,srv->id)," [!] dcw error from cs378x server (%s:%d), ecm not found!!!\n",srv->host->name,srv->port); break; } // srv->busy = 0; pipe_cmd( prg.pipe.ecm[1], PIPE_SRV_AVAILABLE ); pthread_mutex_lock(&prg.lockecm); //### // check for ECM validity if (ecm->hash!=srv->ecm.hash) { debugf(getdbgflag(DBG_SERVER,0,srv->id)," [!] dcw error from cs378x server (%s:%d), ecm deleted!!!\n",srv->host->name,srv->port); pthread_mutex_unlock(&prg.lockecm); break; } cs= ecm->cs; ecm_setsrvflag(ecm, srv->id, ECM_SRV_REPLY_FAIL); debugf(getdbgflagpro(DBG_SERVER,0,srv->id,ecm->cs->id)," <| decode failed from cs378x server (%s:%d) ch %04x:%06x:%04x (%dms)\n", srv->host->name,srv->port, ecm->caid,ecm->provid,ecm->sid, GetTickCount()-srv->lastecmtime); #ifdef SID_FILTER // ADD IN SID LIST if (cs) { cardsids_update( srv->busycard, ecm->provid, ecm->sid, -1); srv_cstatadd( srv, cs->id, 0 , 0); } #endif pthread_mutex_unlock(&prg.lockecm); //### wakeup_sendecm(); // Wakeup ecm waiting for availabe servers break; // Keepalive case CAMD_KEEPALIVE: srv->keepalive.status = 0; //debugf(getdbgflag(DBG_SERVER,0,srv->id)," server(cs378x): Keepalive from (%s:%d)\n", srv->host->name, srv->port); if (srv->connection.status<=0) { debugf(getdbgflag(DBG_SERVER,0,srv->id)," Connected to cs378x server (%s:%d)\n", srv->host->name, srv->port); srv->connection.status = 1; srv->connection.time = GetTickCount(); } break; #ifdef CACHEEX // Request Nodeid case CAMD_CEX_IDREPLY: srv->keepalive.status = 0; //debugf(getdbgflag(DBG_SERVER,0,srv->id)," server(cs378x): Got Nodeid from (%s:%d)\n", srv->host->name, srv->port); memcpy( srv->nodeid, buf+24, 8); if (srv->connection.status<=0) { char str[8*3+1]; array2hex( srv->nodeid, str, 8); debugf(getdbgflag(DBG_SERVER,0,srv->id)," Connected to cs378x server (%s:%d), Nodeid = %s\n", srv->host->name, srv->port, str); srv->connection.status = 1; srv->connection.time = GetTickCount(); } break; // push out case CAMD_CEX_PUSH: if (newlen<60) break; memcpy( cw, buf+44, 16); if (!acceptDCW(cw)) break; //srv->cacheex.totalrep++; struct cache_data cacheex; cacheex.sid = (buf[12]<<8)|buf[13]; cacheex.caid = (buf[14]<<8)|buf[15]; cacheex.provid = (buf[16]<<24)|(buf[17]<<16)|(buf[18]<<8)|buf[19]; // Look for cardserver cs = getcsbycaprovid(cacheex.caid, cacheex.provid); if ( !cs || !cs->option.fallowcacheex ) { srv->cacheex.badcw++; break; } if ((buf[23]&0xFE)==0x80) cacheex.tag = buf[23]; else cacheex.tag = 0; memcpy( cacheex.ecmd5, buf+24, 16); //if ( !checkECMD5(cacheex.ecmd5) ) cli->cacheex.totalcsp++; cacheex.hash = (buf[43]<<24) | (buf[42]<<16) | (buf[41]<<8) | buf[40]; if (!cacheex_check(&cacheex)) break; //debugf(getdbgflag(DBG_SERVER,0,srv->id), " CACHEEX PUSH from client(%d) %04x:%06x:%04x (%08x)\n",cli->id,cacheex.caid,cacheex.provid,cacheex.sid,cacheex.hash); srv->cacheex.got[0]++; int uphop = buf[60]; if (uphop<10) srv->cacheex.got[uphop]++; // 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, nodeid); //cacheex_push(&cacheex, cw, nodeid); } } //debugf(getdbgflag(DBG_SERVER,0,srv->id), " cs378x: push out from server %04x:%06x:%04x|%02x:%08x\n", cacheex.caid,cacheex.provid,cacheex.sid, cacheex.tag,cacheex.hash); break; #endif } srv->keepalive.time = GetTickCount(); return NULL; } /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // CACHEEX MODE 2 void *cs378x_srv_recvmsg_thread(struct server_data *srv) { srv->pid = syscall(SYS_gettid); while (!prg.restart) { if (srv->handle<=0) { srv->pid = 0; disconnect_srv(srv); return NULL; } // struct pollfd pfd; pfd.fd = srv->handle; pfd.events = POLLIN | POLLPRI; int retval = poll(&pfd, 1, 3009); if (retval==0) continue; if (retval<0) { disconnect_srv(srv); return NULL; } // cs378x_srv_recvmsg( srv ); } return NULL; } /////////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////// int cs378x_connect_srv(struct server_data *srv, int fd) { srv->handle = fd; SetSocketTimeout(fd, 5000); cs378x_send_keepalive(srv); srv->handle = 0; // Poll struct pollfd pfd; pfd.fd = fd; pfd.events = POLLIN | POLLPRI; if ( poll( &pfd, 1, 3000) <=0 ) return 1; // unsigned char buf[1024]; int n = cs378x_recv( fd, srv->ucrc, &srv->decryptkey, buf); if (n>0) { #ifdef CACHEEX if ( buf[4] == CAMD_CEX_IDREPLY ) { memcpy( srv->nodeid, buf+24, 8); //debugf(getdbgflag(DBG_SERVER,0,srv->id)," server(cs378x): Got Nodeid from (%s:%d)\n", srv->host->name, srv->port); srv->connection.status = 1; srv->connection.time = GetTickCount(); srv->keepalive.status = 0; srv->keepalive.time = GetTickCount(); srv->handle = fd; // char str[8*3+1]; array2hex( srv->nodeid, str, 8); debugf(getdbgflag(DBG_SERVER,0,srv->id)," Connected to cs378x server (%s:%d), Nodeid = %s\n", srv->host->name, srv->port, str); // Cache EX 2 -> thread if (srv->cacheex_mode==2) { if (!create_thread(&srv->tid, (threadfn)cs378x_srv_recvmsg_thread, srv)) { disconnect_srv(srv); return 1; } } return 0; } else #endif if ( buf[4] == CAMD_KEEPALIVE ) { // debugf(getdbgflag(DBG_SERVER,0,srv->id)," Connected to cs378x server (%s:%d)\n", srv->host->name, srv->port); srv->connection.status = 1; srv->connection.time = GetTickCount(); srv->keepalive.status = 0; srv->keepalive.time = GetTickCount(); srv->handle = fd; //SetUP Cards int count = 0; while (srv->sharelimits[count].caid!=0xFFFF) { struct cs_card_data *pcard = malloc( sizeof(struct cs_card_data) ); memset(pcard, 0, sizeof(struct cs_card_data) ); pcard->caid = srv->sharelimits[count].caid; pcard->nbprov = 1; pcard->prov[0] = srv->sharelimits[count].provid; pcard->uphops = srv->sharelimits[count].uphops; pcard->next = srv->card; srv->card = pcard; count++; } #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; } } return 1; }