./ 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;
}