./ MultiCS.r82 / srv-cccam.c
/////////////////////////////////////////////////////////////////////////////// // File: srv-cccam.c /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // PROTO /////////////////////////////////////////////////////////////////////////////// void cc_senddcw_cli(struct cc_client_data *cli); struct cccam_server_data *getcccamserverbyid(uint32_t id) { struct cccam_server_data *cccam = cfg.cccam.server; while (cccam) { if (!(cccam->flags&FLAG_DELETE)) if (cccam->id==id) return cccam; cccam = cccam->next; } return NULL; } struct cc_client_data *getcccamclientbyid(uint32_t id) { struct cccam_server_data *cccam = cfg.cccam.server; while (cccam) { if (!(cccam->flags&FLAG_DELETE)) { struct cc_client_data *cli = cccam->client; while (cli) { if (!(cli->flags&FLAG_DELETE)) if (cli->id==id) return cli; cli = cli->next; } cli = cccam->cacheexclient; while (cli) { if (!(cli->flags&FLAG_DELETE)) if (cli->id==id) return cli; cli = cli->next; } } cccam = cccam->next; } return NULL; } struct cc_client_data *getcecccamclientbyid(uint32_t id) { struct cccam_server_data *cccam = cfg.cccam.server; while (cccam) { if (!(cccam->flags&FLAG_DELETE)) { struct cc_client_data *cli = cccam->cacheexclient; while (cli) { if (!(cli->flags&FLAG_DELETE)) if (cli->id==id) { debugf(0, "found cccam cacheex client '%s'\n", cli->user); return cli; } cli = cli->next; } } cccam = cccam->next; } return NULL; } struct cc_client_data *getcccamclientbyname(struct cccam_server_data *cccam, char *name) { if (!(cccam->flags&FLAG_DELETE)) { uint32_t hash = hashCode( (unsigned char *)name, strlen(name) ); struct cc_client_data *cli = cccam->client; while (cli) { if (!(cli->flags&FLAG_DELETE)) if (cli->userhash==hash) if ( !strcmp(cli->user,name) ) return cli; cli = cli->next; } } return NULL; } /////////////////////////////////////////////////////////////////////////////// // CCCAM SERVER: DISCONNECT CLIENTS /////////////////////////////////////////////////////////////////////////////// void cc_disconnect_cli(struct cc_client_data *cli) { cli->connection.status = 0; uint32_t ticks = GetTickCount(); cli->connection.uptime += ticks - cli->connection.time; cli->connection.lastseen = ticks; // Last Seen close(cli->handle); cli->handle = -1; cli->parent->clipfd.update = 1; debugf(0," CCcam: client '%s' disconnected \n", cli->user); } /////////////////////////////////////////////////////////////////////////////// // CCCAM SERVER: CONNECT CLIENTS /////////////////////////////////////////////////////////////////////////////// unsigned int seed; uint8_t fast_rnd() { unsigned int offset = 12923; unsigned int multiplier = 4079; seed = seed * multiplier + offset; return (uint8_t)(seed % 0xFF); } /////////////////////////////////////////////////////////////////////////////// int cc_sendinfo_cli(struct cc_client_data *cli, int sendversion) { uint8_t buf[CC_MAXMSGSIZE]; memset(buf, 0, CC_MAXMSGSIZE); memcpy(buf, cfg.cccam.nodeid, 8 ); memcpy(buf + 8, cfg.cccam.version, 32); // cccam version (ascii) memcpy(buf + 40, cfg.cccam.build, 32); // build number (ascii) if (sendversion) { buf[38] = REVISION >> 8; buf[37] = REVISION & 0xff; buf[36] = 0; buf[35] = 'S'; buf[34] = 'C'; buf[33] = 'M'; } //debugdump(cfg.cccam.nodeid,8,"Sending server data version: %s, build: %s nodeid ", cfg.cccam.version, cfg.cccam.build); return cc_msg_send( cli->handle, &cli->sendblock, CC_MSG_SRV_INFO, 0x48, buf); } /////////////////////////////////////////////////////////////////////////////// int cc_sendcard_del(struct cardserver_data *cs, struct cc_client_data *cli) { uint8_t buf[4]; buf[0] = cs->id >> 24; buf[1] = cs->id >> 16; buf[2] = cs->id >> 8; buf[3] = cs->id & 0xff; return cc_msg_send( cli->handle, &cli->sendblock, CC_MSG_CARD_DEL, 4, buf); } int cc_sendcard_cli(struct cardserver_data *cs, struct cc_client_data *cli, int uphops) { uint8_t buf[CC_MAXMSGSIZE]; memset(buf, 0, sizeof(buf)); buf[0] = cs->id >> 24; buf[1] = cs->id >> 16; buf[2] = cs->id >> 8; buf[3] = cs->id & 0xff; buf[4] = cs->id >> 24; buf[5] = cs->id >> 16; buf[6] = cs->id >> 8; buf[7] = cs->id & 0xff; buf[8] = cs->card.caid >> 8; buf[9] = cs->card.caid & 0xff; buf[10] = uphops; buf[11] = cli->dnhops; // Dnhops //buf[20] = cs->card.nbprov; int j; int nbprov = 0; for (j=0; j<cs->card.nbprov; j++) { if ( card_sharelimits(cli->sharelimits, cs->card.caid, cs->card.prov[j].id) ) { //memcpy(buf + 21 + (j*7), card->provs[j], 7); buf[21+nbprov*7] = 0xff&(cs->card.prov[j].id>>16); buf[22+nbprov*7] = 0xff&(cs->card.prov[j].id>>8); buf[23+nbprov*7] = 0xff&(cs->card.prov[j].id); /* buf[24+nbprov*7] = 0xff&(cs->card.prov[j].ua>>24); buf[25+nbprov*7] = 0xff&(cs->card.prov[j].ua>>16); buf[26+nbprov*7] = 0xff&(cs->card.prov[j].ua>>8); buf[27+nbprov*7] = 0xff&(cs->card.prov[j].ua); */ nbprov++; } } if (!nbprov) return 0; // Denied buf[20] = nbprov; buf[21 + (nbprov*7)] = 1; memcpy(buf + 22 + (nbprov*7), cfg.cccam.nodeid, 8); return cc_msg_send( cli->handle, &cli->sendblock, CC_MSG_CARD_ADD, 30 + (nbprov*7), buf); } /////////////////////////////////////////////////////////////////////////////// void cc_sendcards_cli(struct cc_client_data *cli) { int nbcard=0; struct cardserver_data *cs = cfg.cardserver; int i; if (cli->csport[0]) { for(i=0;i<MAX_CSPORTS;i++) { if(cli->csport[i]) { cs = getcsbyport(cli->csport[i]); if ( cs && cs->option.fsharecccam && !(cli->flags&FLAG_EXPIRED) ) if (cc_sendcard_cli(cs, cli,0)) nbcard++; } else break; } } else if (cfg.cccam.csport[0]) { for(i=0;i<MAX_CSPORTS;i++) { if(cfg.cccam.csport[i]) { cs = getcsbyport(cfg.cccam.csport[i]); if ( cs && cs->option.fsharecccam && !(cli->flags&FLAG_EXPIRED) ) if (cc_sendcard_cli(cs, cli,0)) nbcard++; } else break; } } else { while (cs) { if ( cs->option.fsharecccam && !(cli->flags&FLAG_EXPIRED) ) if (cc_sendcard_cli(cs, cli,0)) nbcard++; cs = cs->next; } } debugf(getdbgflag(DBG_CCCAM,cli->parent->id,cli->id)," CCcam: %d cards --> client(%s)\n", nbcard, cli->user); } /////////////////////////////////////////////////////////////////////////////// void *cacheex_cc_cli_recvmsg(struct cc_client_data *cli); void *cc_connect_cli(struct connect_cli_data *param) { uint8_t buf[CC_MAXMSGSIZE]; uint8_t data[64]; int i; struct cc_crypt_block sendblock; // crypto state block struct cc_crypt_block recvblock; // crypto state block char usr[64]; char pwd[255]; // Store data from param struct cccam_server_data *cccam = param->server; int sock = param->sock; uint32_t ip = param->ip; free(param); #ifdef IPLIST struct ip_hacker_data *ipdata = iplist_find( cccam->iplist, ip ); if (ipdata) iplist_newlogin( ipdata ); #endif // struct cc_client_data tmpcli; memset(usr, 0, sizeof(usr)); memset(pwd, 0, sizeof(pwd)); // create & send random seed for(i=0; i<12; i++ ) data[i]=fast_rnd(); // Create Multics ID data[3] = (data[0]^'M') + data[1] + data[2]; data[7] = data[4] + (data[5]^'C') + data[6]; data[11] = data[8] + data[9] + (data[10]^'S'); //Create checksum for "O" cccam: for (i = 0; i < 4; i++) { data[12 + i] = (data[i] + data[4 + i] + data[8 + i]) & 0xff; } #ifdef DEBUG_NETWORK if (flag_debugnet) { debugf(getdbgflag(DBG_CCCAM,cccam->id,0)," CCcam%d: Send Random Key 16\n", cccam->id); debughex(data, 16); } #endif if ( !send_nonb(sock, data, 16, 500) ) { close(sock); return NULL; } //XOR init bytes with 'CCcam' cc_crypt_xor(data); #ifdef DEBUG_NETWORK if (flag_debugnet) { debugf(0, " CCcam: XOR init bytes with 'CCcam'\n"); debughex(data, 16); } #endif //SHA1 SHA_CTX ctx; SHA1_Init(&ctx); SHA1_Update(&ctx, data, 16); SHA1_Final(buf, &ctx); //init crypto states cc_crypt_init(&sendblock, buf, 20); cc_decrypt(&sendblock, data, 16); //debugf(getdbgflag(DBG_CCCAM,cccam->id,0)," CCcam%d: sendblock:cc_crypt_init \n", cccam->id); debughex(sendblock.keytable,256); cc_crypt_init(&recvblock, data, 16); cc_decrypt(&recvblock, buf, 20); //debugf(getdbgflag(DBG_CCCAM,cccam->id,0)," CCcam%d: recvblock:cc_crypt_init \n", cccam->id); debughex(recvblock.keytable,256); #ifdef DEBUG_NETWORK if (flag_debugnet) { debugf(getdbgflag(DBG_CCCAM,cccam->id,0)," CCcam: SHA1 hash\n"); debughex(buf,20); } #endif memcpy(usr,buf,20); if ((i=recv_nonb(sock, buf, 20,5000)) == 20) { #ifdef DEBUG_NETWORK if (flag_debugnet) { debugf(getdbgflag(DBG_CCCAM,cccam->id,0)," CCcam%d: receive SHA1 hash %d\n", cccam->id, i); debughex(buf,i); } #endif cc_decrypt(&recvblock, buf, 20); #ifdef DEBUG_NETWORK if (flag_debugnet) { debugf(getdbgflag(DBG_CCCAM,cccam->id,0)," Decrypted SHA1 hash (20):\n"); debughex(buf,20); } #endif if ( memcmp(buf,usr,20)!=0 ) { //debugf(getdbgflag(DBG_CCCAM,cccam->id,0)," cc_connect_cli(): wrong sha1 hash from client! (%s)\n",ip2string(ip)); close(sock); return NULL; } } else { debugf(getdbgflag(DBG_CCCAM,cccam->id,0)," cc_connect_cli(): recv sha1 timeout\n"); close(sock); return NULL; } // receive username i = recv_nonb(sock, buf, 20,5000); #ifdef DEBUG_NETWORK if (flag_debugnet) { debugf( getdbgflag(DBG_CCCAM,cccam->id,0) , " CCcam%d: receive username %s -%d\n", cccam->id, ip2string(ip), i); debughex(buf,i); } #endif if (i == 20) { cc_decrypt(&recvblock, buf, i); memcpy(usr,buf,20); usr[20] = 0; //strcpy(usr, (char*)buf); //debugf(getdbgflag(DBG_CCCAM,cccam->id,0)," cc_connect_cli(): username '%s'\n", usr); } else { //debugf(getdbgflag(DBG_CCCAM,cccam->id,0)," cc_connect_cli(): recv user timeout\n"); close(sock); return NULL; } // test username for(i=0; i<20; i++) { if (usr[i]==0) break; if (usr[i]<=32) { // bad username close(sock); return NULL; } } // Check for username ///pthread_mutex_lock(&prg.lockcccli); int found = 0; uint32_t hash = hashCode( (unsigned char *)usr, strlen(usr) ); struct cc_client_data *cli = cccam->client; while (cli) { if (cli->userhash==hash) if (!strcmp(cli->user,usr)) { if (IS_DISABLED(cli->flags)) { // Connect only enabled clients ///pthread_mutex_unlock(&prg.lockcccli); debugf(getdbgflag(DBG_CCCAM,cli->parent->id,cli->id)," CCcam%d: connection refused for client '%s' (%s), client disabled\n", cccam->id, usr, ip2string(ip)); close(sock); return NULL; } found = 1; break; } cli = cli->next; } if (!found) { cli = cccam->cacheexclient; while (cli) { if (cli->userhash==hash) if (!strcmp(cli->user,usr)) { if (IS_DISABLED(cli->flags)) { // Connect only enabled clients ///pthread_mutex_unlock(&prg.lockcccli); debugf(getdbgflag(DBG_CCCAM,cli->parent->id,cli->id)," CCcam%d: connection refused for cacheexclient '%s' (%s), client disabled\n", cccam->id, usr, ip2string(ip)); close(sock); return NULL; } found = 1; break; } cli = cli->next; } } ///pthread_mutex_unlock(&prg.lockcccli); if (!found) { debugf(getdbgflag(DBG_CCCAM,cccam->id,0)," CCcam%d: Unknown Client '%s' (%s)\n", cccam->id, usr, ip2string(ip)); close(sock); return NULL; } memcpy( &tmpcli, cli, sizeof(struct cc_client_data)); // Check for Host if (cli->host) { struct host_data *host = cli->host; host->clip = ip; if ( host->ip && (host->ip!=ip) ) { uint32_t sec = getseconds()+60; if ( host->checkiptime > sec ) host->checkiptime = sec; debugf(getdbgflag(DBG_CCCAM,cli->parent->id,cli->id)," CCcam%d: Aborted connection from Client '%s' (%s), ip refused\n", cccam->id, usr, ip2string(ip)); cli->nbloginerror++; close(sock); return NULL; } } // Encrypted Password if ((i=recv_nonb(sock, buf, 6,5000)) == 6) { memset(pwd, 0, sizeof(pwd)); strcpy(pwd, cli->pass); cc_encrypt(&recvblock, (uint8_t*)pwd, strlen(pwd)); cc_decrypt(&recvblock, buf, 6); if ( memcmp(buf,"CCcam\0",6) ) { debugf(getdbgflag(DBG_CCCAM,cli->parent->id,cli->id)," CCcam%d: login failed from client '%s'\n", cccam->id, usr); cli->nbloginerror++; close(sock); return NULL; } } else { debugf(getdbgflag(DBG_CCCAM,cli->parent->id,cli->id)," CCcam%d: login failed from client '%s', error receiving crypted password\n", cccam->id, usr); cli->nbloginerror++; close(sock); return NULL; } if (cli->ip==ip) cli->nbdiffip++; // Send passwd ack memset(buf, 0, 20); memcpy(buf, "CCcam\0", 6); //debugf(getdbgflag(DBG_CCCAM,cli->parent->id,cli->id),"Server: send ack '%s'\n",buf); cc_encrypt(&sendblock, buf, 20); if (!send_nonb(sock, buf, 20, 100) ) { close(sock); return NULL; } memcpy(&tmpcli.sendblock,&sendblock,sizeof(sendblock)); memcpy(&tmpcli.recvblock,&recvblock,sizeof(recvblock)); debugf(getdbgflag(DBG_CCCAM,cli->parent->id,cli->id)," CCcam%d: client '%s' connected\n", cccam->id, usr); // Recv cli data memset(buf, 0, sizeof(buf)); i = cc_msg_recv( sock, &tmpcli.recvblock, buf, 5000); if ( i<65 ) { debugf(getdbgflag(DBG_CCCAM,cli->parent->id,cli->id)," CCcam%d: Error recv cli '%s' data (%d/%d)\n", cccam->id, cli->user, i, errno); debughex(buf,i); close(sock); return NULL; } // Setup Client Data // pthread_mutex_lock(&prg.lockcccli); memcpy( tmpcli.nodeid, buf+24, 8); memcpy( tmpcli.version, buf+33, 31); memcpy( tmpcli.build, buf+65, 31 ); debugf(getdbgflag(DBG_CCCAM,cli->parent->id,cli->id)," CCcam%d: client '%s' running version %s build %s\n", cccam->id, usr, tmpcli.version, tmpcli.build); // cli->nodeid,8, // Check for Nodeid/CCcam Version if (cli->option.checknodeid) if (cli->option.nodeid[0] && cli->option.nodeid[7]) { if (memcmp(cli->option.nodeid, tmpcli.nodeid, 8)) { // diff nodeid debugf(getdbgflag(DBG_CCCAM,cli->parent->id,cli->id)," CCcam%d: login failed from client '%s' (%s), wrong nodeid\n", cccam->id, usr, ip2string(ip)); cli->nbloginerror++; close(sock); return NULL; } } //Check Reconnection if (cli->connection.status>0) { if ( (GetTickCount()-cli->connection.time) > 60000 ) { cc_disconnect_cli(cli); if (cli->ip==ip) debugf(getdbgflag(DBG_CCCAM,cli->parent->id,cli->id)," CCcam%d: Client '%s' (%s) already connected\n", cccam->id, usr, ip2string(ip)); else { debugf(getdbgflag(DBG_CCCAM,cli->parent->id,cli->id)," CCcam%d: Client '%s' (%s) already connected with different ip, Connection closed.\n", cccam->id, usr, ip2string(ip)); cli->nbloginerror++; close(sock); return NULL; } } else { debugf(getdbgflag(DBG_CCCAM,cli->parent->id,cli->id)," CCcam%d: Client '%s' just connected, new connection closed (%s)\n", cccam->id, usr, ip2string(ip)); cli->nbloginerror++; close(sock); return NULL; } } cli->nblogin++; #ifdef IPLIST if (ipdata) iplist_goodlogin(ipdata); #endif memcpy(&cli->sendblock, &tmpcli.sendblock,sizeof(tmpcli.sendblock)); memcpy(&cli->recvblock, &tmpcli.recvblock,sizeof(tmpcli.recvblock)); memcpy(cli->nodeid, tmpcli.nodeid, 8); // store nodeid if not set :) if (!cli->option.nodeid[0] && !cli->option.nodeid[7]) { memcpy(cli->option.nodeid, tmpcli.nodeid, 8); prg.updatenodes = 1; } memcpy(cli->version, tmpcli.version, 31); memcpy(cli->build, tmpcli.build, 31 ); cli->cardsent = 0; memset( &cli->ecm, 0, sizeof(cli->ecm) ); memset( &cli->lastecm, 0, sizeof(cli->lastecm) ); cli->handle = sock; cli->connection.status = 1; cli->connection.time = cli->lastactivity = GetTickCount(); cli->lastecmtime = 0; cli->chkrecvtime = 0; cli->ip = ip; cli->msg.len = 0; // pthread_mutex_unlock(&prg.lockcccli); // send cli data ack cc_msg_send( sock, &cli->sendblock, CC_MSG_CLI_INFO, 0, NULL); //cc_msg_send( sock, &cli->sendblock, CC_MSG_BAD_ECM, 0, NULL); int sendversion = ( (cli->version[28]=='W')&&(cli->version[29]='H')&&(cli->version[30]='O') ); cc_sendinfo_cli(cli, sendversion); //cc_msg_send( sock, &cli->sendblock, CC_MSG_BAD_ECM, 0, NULL); cli->cardsent = 1; //TODO: read from client packet CC_MSG_BAD_ECM //len = cc_msg_recv(cli->handle, &cli->recvblock, buf, 3); usleep(55000); #ifdef CACHEEX if (!cli->cacheex_mode) #endif cc_sendcards_cli(cli); cli->handle = sock; #ifdef CACHEEX if (cli->cacheex_mode==3) { if (!create_thread( &cli->tid, (threadfn)cacheex_cc_cli_recvmsg, cli )) { cc_disconnect_cli(cli); return NULL; } } else if (cli->cacheex_mode) pipe_wakeup( prg.pipe.cacheex[1] ); else #endif #ifdef EPOLL_CCCAM pipe_pointer( prg.pipe.cccam[1], PIPE_CLI_CONNECTED, cli ); #else pipe_wakeup( prg.pipe.cccam[1] ); #endif // update pfd data ??? cli->parent->clipfd.update = 1; return cli; } //////////////////////////////////////////////////////////////////////////////// void cccam_srv_accept(struct cccam_server_data *srv) { struct sockaddr_in newaddr; socklen_t socklen = sizeof(struct sockaddr); int newfd = accept( srv->handle, (struct sockaddr*)&newaddr, /*(socklen_t*)*/&socklen); if ( newfd<=0 ) { if ( (errno!=EAGAIN) && (errno!=EINTR) ) debugf( getdbgflag(DBG_CCCAM,srv->id,0)," CCcam%d: Accept failed (errno=%d)\n", srv->id,errno); } else { SetSocketReuseAddr(newfd); uint32_t newip = newaddr.sin_addr.s_addr; #ifdef IPLIST struct ip_hacker_data *ipdata = iplist_find( srv->iplist, newip ); if (!ipdata) { ipdata = iplist_add( newip ); ipdata->next = srv->iplist; srv->iplist = ipdata; } #endif if ( isblockedip(newip) ) { debugf(getdbgflag(DBG_CCCAM,srv->id,0)," CCcam%d: New Connection (%s) closed, ip blocked\n", srv->id, ip2string(newip) ); close(newfd); } #ifdef IPLIST else if ( !iplist_accept( ipdata ) ) { debugf(getdbgflag(DBG_CCCAM,srv->id,0)," CCcam%d: New Connection (%s) closed, ip temporary blocked\n", srv->id, ip2string(newip) ); close(newfd); } #endif else { pthread_t srv_tid; if (cfg.cccam.keepalive) SetSocketKeepalive(newfd); SetSocketNoDelay(newfd); SetSoketNonBlocking(newfd); //debugf(getdbgflag(DBG_CCCAM,srv->id,0)," CCcam%d: new connection (%s)\n", srv->id, ip2string(newip) ); struct connect_cli_data *newdata = malloc( sizeof(struct connect_cli_data) ); newdata->server = srv; newdata->sock = newfd; newdata->ip = newaddr.sin_addr.s_addr; if ( !create_thread(&srv_tid, (threadfn)cc_connect_cli,newdata) ) { free( newdata ); close( newfd ); } } } } void *cccam_accept_thread(void *param) { prctl(PR_SET_NAME,"CCcam Accept",0,0,0); sleep(5); while(!prg.restart) { struct pollfd pfd[18]; int pfdcount = 0; struct cccam_server_data *cccam = cfg.cccam.server; while (cccam) { if ( !IS_DISABLED(cccam->flags) && (cccam->handle>0) ) { cccam->ipoll = pfdcount; pfd[pfdcount].fd = cccam->handle; pfd[pfdcount++].events = POLLIN | POLLPRI; } else cccam->ipoll = -1; cccam = cccam->next; } if (pfdcount) { int retval = poll(pfd, pfdcount, 3006); if ( retval>0 ) { struct cccam_server_data *cccam = cfg.cccam.server; while (cccam) { if ( !IS_DISABLED(cccam->flags) && (cccam->handle>0) && (cccam->ipoll>=0) && (cccam->handle==pfd[cccam->ipoll].fd) ) { if ( pfd[cccam->ipoll].revents & (POLLIN|POLLPRI) ) cccam_srv_accept(cccam); } cccam = cccam->next; } } else if (retval<0) usleep(96000); } else sleep(1); } return NULL; } //////////////////////////////////////////////////////////////////////////////// // CCCAM SERVER: SEND DCW TO CLIENTS //////////////////////////////////////////////////////////////////////////////// void cc_senddcw_cli(struct cc_client_data *cli) { uint8_t buf[CC_MAXMSGSIZE]; uint32_t ticks = GetTickCount(); if (cli->ecm.status==STAT_DCW_SENT) { debugf(getdbgflag(DBG_CCCAM,cli->parent->id,cli->id)," +> cw send failed to CCcam client '%s', cw already sent\n", cli->user); return; } if (cli->handle<=0) { debugf(getdbgflag(DBG_CCCAM,cli->parent->id,cli->id)," +> cw send failed to CCcam client '%s', client disconnected\n", cli->user); return; } if (!cli->ecm.busy) { debugf(getdbgflag(DBG_CCCAM,cli->parent->id,cli->id)," +> cw send failed to CCcam client '%s', no ecm request\n", cli->user); return; } ECM_DATA *ecm = cli->ecm.request; //FREEZE int samechannel = (cli->lastecm.caid==ecm->caid)&&(cli->lastecm.prov==ecm->provid)&&(cli->lastecm.sid==ecm->sid); int enablefreeze=0; if (samechannel) { if ( (cli->lastecm.hash!=ecm->hash)&&(cli->lastecm.tag!=ecm->ecm[0]) ) if ( (cli->lastecm.status=1)&&(cli->lastdcwtime+200<ticks) ) enablefreeze = 1; } else cli->zap++; // cli->lastecm.caid = ecm->caid; cli->lastecm.prov = ecm->provid; cli->lastecm.sid = ecm->sid; cli->lastecm.hash = ecm->hash; cli->lastecm.tag = ecm->ecm[0]; cli->lastecm.decodetime = ticks-cli->ecm.recvtime; cli->lastecm.request = cli->ecm.request; if ( (ecm->dcwstatus==STAT_DCW_SUCCESS)&&(ecm->hash==cli->ecm.hash) ) { cli->lastecm.dcwsrctype = ecm->dcwsrctype; cli->lastecm.dcwsrcid = ecm->dcwsrcid; cli->lastecm.status=1; cli->ecmok++; cli->lastdcwtime = ticks; cli->ecmoktime += ticks-cli->ecm.recvtime; //cli->lastecmoktime = ticks-cli->ecm.recvtime; memcpy( buf, ecm->cw, 16 ); cc_crypt_cw( cli->nodeid, cli->ecm.cardid , buf); if ( !cc_msg_send( cli->handle, &cli->sendblock, CC_MSG_ECM_REQUEST, 16, buf) ) { cc_disconnect_cli( cli ); return; } cc_encrypt(&cli->sendblock, buf, 16); // additional crypto step debugf(getdbgflagpro(DBG_CCCAM,cli->parent->id,cli->id,ecm->cs->id)," => cw to CCcam client '%s' ch %04x:%06x:%04x (%dms)\n", cli->user, ecm->caid,ecm->provid,ecm->sid, ticks-cli->ecm.recvtime); } else { //if (ecm->data->dcwstatus==STAT_DCW_FAILED) if (enablefreeze) { cli->freeze++; } cli->lastecm.dcwsrctype = DCW_SOURCE_NONE; cli->lastecm.dcwsrcid = 0; cli->lastecm.status=0; if ( !cc_msg_send( cli->handle, &cli->sendblock, CC_MSG_ECM_NOK1, 0, NULL) ) { cc_disconnect_cli( cli ); return; } debugf(getdbgflagpro(DBG_CCCAM,cli->parent->id,cli->id,ecm->cs->id)," |> decode failed to CCcam client '%s' ch %04x:%06x:%04x (%dms)\n", cli->user, ecm->caid,ecm->provid,ecm->sid, ticks-cli->ecm.recvtime); } cli->ecm.busy=0; cli->ecm.status = STAT_DCW_SENT; } /////////////////////////////////////////////////////////////////////////////// // Check sending cw to clients void cc_check_sendcw(ECM_DATA *ecm) { struct cccam_server_data *cccam = cfg.cccam.server; while (cccam) { if ( !IS_DISABLED(cccam->flags) && (cccam->handle>0) ) { struct cc_client_data *cli = cccam->client; while (cli) { if ( !IS_DISABLED(cli->flags)&&(cli->connection.status>0)&&(cli->ecm.busy)&&(cli->ecm.request==ecm) ) { cc_senddcw_cli( cli ); } cli = cli->next; } } cccam = cccam->next; } } /////////////////////////////////////////////////////////////////////////////// // CCCAM SERVER: RECEIVE MESSAGES FROM CLIENTS /////////////////////////////////////////////////////////////////////////////// void cc_store_ecmclient(ECM_DATA *ecm, struct cc_client_data *cli) { uint32_t ticks = GetTickCount(); cli->ecm.recvtime = ticks; cli->ecm.request = ecm; cli->ecm.status = STAT_ECM_SENT; ecm_addip(ecm, cli->ip); } /////////////////////////////////////////////////////////////////////////////// // Receive messages from client void cc_cli_parsemsg(struct cc_client_data *cli, uint8_t *buf, int len) { if (len>=CC_MAXMSGSIZE) return; uint8_t data[CC_MAXMSGSIZE]; // for other use uint8_t cw[16]; unsigned int cardid; uint32_t ticks = GetTickCount(); cli->lastactivity = ticks; switch (buf[1]) { case CC_MSG_ECM_REQUEST: cli->ecmnb++; cli->lastecmtime = ticks; if (len<20) return; // Avoid malicious peers /* if (cli->ecm.busy) { // send decode failed cli->ecmdenied++; if ( !cc_msg_send( cli->handle, &cli->sendblock, CC_MSG_ECM_NOK1, 0, NULL) ) { debugf(getdbgflag(DBG_ERROR,0,0)," Error encountred when sending failedcw to client '%s'\n", cli->user); cc_disconnect_cli(cli); return; } debugf(getdbgflag(DBG_CCCAM,cli->parent->id,cli->id)," <|> decode failed to CCcam client '%s', too many ecm requests\n", cli->user); break; } */ cli->ecm.busy = 0; //Check for card availability memcpy( data, buf+17, len-17); cardid = buf[10]<<24 | buf[11]<<16 | buf[12]<<8 | buf[13]; uint16_t caid = buf[4]<<8 | buf[5]; uint16_t sid = buf[14]<<8 | buf[15]; uint32_t provid = ecm_getprovid( data, caid ); if (provid==0) provid = buf[6]<<24 | buf[7]<<16 | buf[8]<<8 | buf[9]; // Check for Profile struct cardserver_data *cs=getcsbyid( cardid ); if (!cs) { // check for cs by caid:prov cs = getcsbycaidprov(caid,provid); if (!cs) { cli->ecmdenied++; if ( !cc_msg_send( cli->handle, &cli->sendblock, CC_MSG_ECM_NOK1, 0, NULL) ) { debugf(getdbgflag(DBG_ERROR,0,0)," Error encountred when sending failedcw to client '%s'\n", cli->user); cc_disconnect_cli(cli); return; } debugf(getdbgflag(DBG_CCCAM,cli->parent->id,cli->id)," <|> decode failed to CCcam client '%s', card-id %x (%04x:%06x) not found\n",cli->user, cardid, caid,provid); break; } } // Check for Share if (!cs->option.fsharecccam) { cli->ecmdenied++; if ( !cc_msg_send( cli->handle, &cli->sendblock, CC_MSG_ECM_NOK1, 0, NULL) ) { debugf(getdbgflag(DBG_ERROR,0,0)," Error encountred when sending failedcw to client '%s'\n", cli->user); cc_disconnect_cli(cli); return; } debugf(getdbgflag(DBG_CCCAM,cli->parent->id,cli->id)," <|> decode failed to CCcam client '%s', Profile '%s' disabled to client\n",cli->user, cs->name); break; } // Chec for ECM uint8_t cw1cycle; char *error = cs_accept_ecm(cs,caid,provid,sid,ecm_getchid(data,caid), len-17, data, &cw1cycle); if (error) { cs->ecmdenied++; cli->ecmdenied++; if (!cc_msg_send( cli->handle, &cli->sendblock, CC_MSG_ECM_NOK1, 0, NULL)) { cc_disconnect_cli(cli); return; } debugf(getdbgflagpro(DBG_CCCAM,cli->parent->id,cli->id,cs->id)," <|> decode failed to CCcam client '%s' ch %04x:%06x:%04x, %s\n", cli->user, caid,provid,sid, error); break; } // ACCEPTED pthread_mutex_lock(&prg.lockecm); // Search for ECM ECM_DATA *ecm = search_ecmdata_any(cs, data, len-17, sid, caid); int isnew = ( ecm==NULL ); if (ecm) { ecm->lastrecvtime = ticks; if (ecm->dcwstatus==STAT_DCW_FAILED) { if (ecm->period > cs->option.dcw.retry) { if ( !cc_msg_send( cli->handle, &cli->sendblock, CC_MSG_ECM_NOK1, 0, NULL) ) { cc_disconnect_cli( cli ); return; } debugf(getdbgflag(DBG_CCCAM,cli->parent->id,cli->id)," <|> decode failed to CCcam client '%s' ch %04x:%06x:%04x:%08x, already failed\n",cli->user, caid, provid, sid, ecm->hash); } else { ecm->period++; // RETRY cc_store_ecmclient(ecm, cli); debugf(getdbgflagpro(DBG_CCCAM,cli->parent->id,cli->id,cs->id)," <- ecm from CCcam client '%s' ch %04x:%06x:%04x:%08x**\n", cli->user, caid, provid, sid, ecm->hash); cli->ecm.busy=1; cli->ecm.hash = ecm->hash; cli->ecm.cardid = cardid; ecm->dcwstatus = STAT_DCW_WAIT; ecm->cachestatus = 0; //ECM_CACHE_NONE; // Resend Request ecm->checktime = 1; // Check NOW pipe_wakeup( prg.pipe.ecm[1] ); } } else { // SUCCESS/WAIT cc_store_ecmclient(ecm, cli); debugf(getdbgflagpro(DBG_CCCAM,cli->parent->id,cli->id,cs->id)," <- ecm from CCcam client '%s' ch %04x:%06x:%04x:%08x*\n", cli->user, caid, provid, sid, ecm->hash); cli->ecm.busy=1; cli->ecm.hash = ecm->hash; cli->ecm.cardid = cardid; if (cli->dcwcheck) { if ( !ecm->lastdecode.ecm && (ecm->lastdecode.ecm!=ecm) ) { checkfreeze_checkECM( ecm, cli->lastecm.request); if (ecm->lastdecode.ecm) pipe_cache_find(ecm, cs); } } // Check for Success/Timeout if (!ecm->checktime) { if (cli->dcwcheck) { if ( (ecm->dcwstatus==STAT_DCW_SUCCESS) && !checkfreeze_setdcw(ecm,ecm->cw) ) { // ??? last ecm is wrong ecm->dcwstatus = STAT_DCW_WAIT; memset( ecm->cw, 0, 16 ); ecm->checktime = 1; // Wakeup Now pipe_wakeup( prg.pipe.ecm[1] ); } else { pthread_mutex_unlock(&prg.lockecm); cc_senddcw_cli(cli); break; } } else { pthread_mutex_unlock(&prg.lockecm); cc_senddcw_cli(cli); break; } } } } else { cs->ecmaccepted++; // Setup ECM Request for Server(s) ecm = store_ecmdata(cs, data, len-17, sid, caid, provid); cc_store_ecmclient(ecm, cli); debugf(getdbgflagpro(DBG_CCCAM,cli->parent->id,cli->id,cs->id)," <- ecm from CCcam client '%s' ch %04x:%06x:%04x:%08x\n",cli->user,caid,provid,sid, ecm->hash); cli->ecm.busy=1; cli->ecm.hash = ecm->hash; cli->ecm.cardid = cardid; ecm->cw1cycle = cw1cycle; ecm->dcwstatus = STAT_DCW_WAIT; #ifdef CHECK_NEXTDCW if (cli->dcwcheck) checkfreeze_checkECM( ecm, cli->lastecm.request); #endif if (cs->option.fallowcache) { ecm->waitcache = 1; ecm->dcwstatus = STAT_DCW_WAITCACHE; ecm->checktime = ecm->recvtime + cs->option.cachetimeout; pipe_cache_find(ecm, cs); } else ecm->checktime = 1; // Check NOW pipe_wakeup( prg.pipe.ecm[1] ); #ifdef TESTCHANNEL int testchannel = ( (ecm->caid==cfg.testchn.caid)&&(ecm->provid==cfg.testchn.provid)&&(!cfg.testchn.sid||(ecm->sid==cfg.testchn.sid)) ); if (testchannel) { fdebugf(" <- ecm from CCcam client '%s' ch %04x:%06x:%04x %02x:%08x\n", cli->user, ecm->caid, ecm->provid, ecm->sid, ecm->ecm[0], ecm->hash); } #endif } pthread_mutex_unlock(&prg.lockecm); if (isnew) wakeup_sendecm(); break; case CC_MSG_KEEPALIVE: if ( !cc_msg_send( cli->handle, &cli->sendblock, CC_MSG_KEEPALIVE, 0, NULL) ) cc_disconnect_cli( cli ); //printf(" Keepalive from client '%s'\n",cli->user); break; #ifdef CACHEEX case CC_MSG_CACHE_PUSH: if (cli->cacheex_mode!=3) break; //if (buf[18]!=0) break; // Got CW memcpy( cw, buf+44, 16); if (!acceptDCW(cw)) break; 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 ) { cli->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; cli->cacheex.got[0]++; int uphop = buf[60]; if (uphop<10) cli->cacheex.got[uphop]++; // // pthread_mutex_lock( &prg.lockcache ); int res = cache_setdcw( &cacheex, cw, NO_CYCLE, PEER_CCCAM_CLIENT | cli->id ); pthread_mutex_unlock( &prg.lockcache ); if (res&DCW_ERROR) { if ( !(res&DCW_SKIP) ) cli->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_CACHEEX, 0, 0)," CACHEEX PUSH from client '%s' %04x:%06x:%04x:%08x\n",cli->user,cacheex.caid,cacheex.provid,cacheex.sid,cacheex.hash); break; #endif case CC_MSG_BAD_ECM: break; default: debugf(0, " unknown message type\n"); debughex(buf, len); } } int cc_cli_peekmsg(struct cc_client_data *cli, uint8_t *buf) { int len; if (cli->handle<=0) return 0; // disconnected #ifdef RECVMSG_PEEK len = cc_msg_chkrecv(cli->handle,&cli->recvblock); uint32_t ticks = GetTickCount(); if (len==0) { debugf(getdbgflag(DBG_CCCAM,cli->parent->id,cli->id)," CCcam: client '%s' read failed %d\n", cli->user,len); cc_disconnect_cli(cli); } else if (len<0) { if (!cli->chkrecvtime) cli->chkrecvtime = ticks; else if ( (cli->chkrecvtime+500)<ticks ) { debugf(getdbgflag(DBG_CCCAM,cli->parent->id,cli->id)," CCcam: client '%s' read failed %d\n", cli->user,len); cc_disconnect_cli(cli); } } else if (len>0) { cli->chkrecvtime = 0; len = cc_msg_recv( cli->handle, &cli->recvblock, buf, 3000); if (len==0) { debugf(getdbgflag(DBG_CCCAM,cli->parent->id,cli->id)," CCcam: client '%s' read failed %d\n", cli->user,len); cc_disconnect_cli(cli); } else if (len<0) { debugf(getdbgflag(DBG_CCCAM,cli->parent->id,cli->id)," CCcam: client '%s' read failed %d(%d)\n", cli->user,len,errno); cc_disconnect_cli(cli); } else return len; } #else len = cc_peekmsg( cli->handle, &cli->recvblock, &cli->msg, buf ); if (len==0) { debugf(getdbgflag(DBG_CCCAM,cli->parent->id,cli->id)," CCcam: client '%s' read failed %d\n", cli->user,len); cc_disconnect_cli(cli); } else if (len==-1) { uint32_t ticks = GetTickCount(); if (!cli->chkrecvtime) cli->chkrecvtime = ticks; else if ( (cli->chkrecvtime+1000)<ticks ) { debugf(getdbgflag(DBG_CCCAM,cli->parent->id,cli->id)," CCcam: client '%s' read failed %d\n", cli->user,len); cc_disconnect_cli(cli); } } else return len; #endif return 0; } // Receive messages from client void *cc_cli_recvmsg(struct cc_client_data *cli) { if (cli->handle<=0) return NULL; //debugf(getdbgflag(DBG_CCCAM,0,0)," CCcam: client '%s' recv msg (len=%d)\n", cli->user, cli->msg.len); uint8_t buf[CC_MAXMSGSIZE]; int len = cc_cli_peekmsg(cli, buf); if (len<=0) return NULL; if (len>=CC_MAXMSGSIZE) return NULL; cli->chkrecvtime = 0; cc_cli_parsemsg(cli, buf, len); return NULL; } #ifdef CACHEEX // Receive messages from CacheEX client void *cacheex_cc_cli_recvmsg(struct cc_client_data *cli) { cli->pid = syscall(SYS_gettid); while (cli->connection.status>0) { struct pollfd pfd; pfd.fd = cli->handle; pfd.events = POLLIN | POLLPRI; int retval = poll(&pfd, 1, 3005); // for 3seconds if (retval==0) continue; else if (retval<0) { // error cc_disconnect_cli(cli); break; } else if ( pfd.revents & (POLLIN|POLLPRI) ) cc_cli_recvmsg(cli); else { cc_disconnect_cli(cli); break; } } cli->pid = 0; return NULL; } #endif void cc_recv_pipe() { struct cccam_server_data *cccam; struct cardserver_data *cs; struct cc_client_data *cli; //debugf(getdbgflag(DBG_CCCAM,0,0)," CCcam: recv_msg from pipe\n"); uint8_t buf[1024]; struct pollfd pfd[2]; do { int len = pipe_recv( prg.pipe.cccam[0], buf); if (len>0) { //debugf(getdbgflag(DBG_CCCAM,0,0)," CCcam: recv_msg from pipe (%d)\n", buf[0]); switch(buf[0]) { case PIPE_WAKEUP: // ADD NEW CLIENT //debugf(" wakeup csmsg\n"); break; #ifdef EPOLL_CCCAM case PIPE_CLI_CONNECTED: // ADD NEW FD memcpy( &cli, buf+1, sizeof(void*) ); // Add to events struct epoll_event ev; // epoll event ev.events = EPOLLIN; ev.data.fd = cli->handle; ev.data.ptr = cli; if ( epoll_ctl(prg.epoll.cccam, EPOLL_CTL_ADD, cli->handle, &ev) == -1 ) debugf(DBG_ERROR,"Err! EPOLL_CTL_ADD %s (%d) %d\n", cli->user, cli->handle, errno); //else debugf(0,"EPOLL_CTL_ADD %s (%d)\n", cli->user, cli->handle); break; #endif case PIPE_CARD_DEL: memcpy( &cs, buf+1, sizeof(void*) ); if (cs) { cccam = cfg.cccam.server; while (cccam) { if ( !IS_DISABLED(cccam->flags)&&(cccam->handle>0) ) { struct cc_client_data *cli = cccam->client; while (cli) { if ( !IS_DISABLED(cli->flags)&&(cli->handle>0) ) cc_sendcard_del(cs, cli); cli = cli->next; } } cccam = cccam->next; } } break; case PIPE_CARD_ADD: memcpy( &cs, buf+1, sizeof(void*) ); if (cs) { cccam = cfg.cccam.server; while (cccam) { if ( !IS_DISABLED(cccam->flags)&&(cccam->handle>0) ) { struct cc_client_data *cli = cccam->client; while (cli) { if ( !IS_DISABLED(cli->flags)&&(cli->handle>0) ) cc_sendcard_cli(cs, cli, 0); cli = cli->next; } } cccam = cccam->next; } } break; } } pfd[0].fd = prg.pipe.cccam[0]; pfd[0].events = POLLIN | POLLPRI; } while (poll(pfd, 1, 3)>0); } /////////////////////////////////////////////////////////////////////////////// #ifdef EPOLL_CCCAM void *cc_recvmsg_thread(void *param) { int i; cfg.cccam.pid_recvmsg = syscall(SYS_gettid); prg.pid_cc_msg = syscall(SYS_gettid); prctl(PR_SET_NAME,"CCcam RecvMSG",0,0,0); struct epoll_event evlist[MAX_EPOLL_EVENTS]; // epoll recv events prg.epoll.cccam = epoll_create( MAX_EPOLL_EVENTS ); // Add PIPE struct epoll_event ev; // epoll event ev.events = EPOLLIN | EPOLLPRI | EPOLLRDHUP; ev.data.ptr = NULL; if ( epoll_ctl(prg.epoll.cccam, EPOLL_CTL_ADD, prg.pipe.cccam[0], &ev) == -1 ) printf("epoll_ctl"); while (!prg.restart) { int ready = epoll_wait( prg.epoll.cccam, evlist, MAX_EPOLL_EVENTS, 1002); if (ready == -1) { if ( (errno==EINTR)||(errno==EAGAIN) ) { usleep(1000); continue; } else { usleep(99000); debugf(DBG_ERROR,"Err! epoll_wait (%d)", errno); } } else if (ready==0) continue; // timeout usleep(cfg.delay.thread); for (i=0; i < ready; i++) { if ( evlist[i].events & (EPOLLIN|EPOLLPRI) ) { if (evlist[i].data.ptr == NULL) cc_recv_pipe(); else cc_cli_recvmsg(evlist[i].data.ptr); } else if ( evlist[i].events & (EPOLLRDHUP | EPOLLHUP | EPOLLERR) ) { // EPOLLRDHUP if (evlist[i].data.ptr == NULL) debugf(DBG_ERROR,"Err! epoll_wait() pipe\n"); // error !!! else cc_disconnect_cli(evlist[i].data.ptr); } } } return NULL; } #else void *cc_recvmsg_thread(void *param) { struct pollfd pfd[MAX_PFD]; int pfdcount; cfg.cccam.pid_recvmsg = syscall(SYS_gettid); prg.pid_cc_msg = syscall(SYS_gettid); prctl(PR_SET_NAME,"CCcam RecvMSG",0,0,0); while (!prg.restart) { pfdcount = 0; // PIPE pfd[pfdcount].fd = prg.pipe.cccam[0]; pfd[pfdcount++].events = POLLIN | POLLPRI; struct cccam_server_data *cccam = cfg.cccam.server; while (cccam) { if ( !IS_DISABLED(cccam->flags)&&(cccam->handle>0) ) { if (cccam->clipfd.update||cccam->clipfd.count<0) { cccam->clipfd.count = 0; struct cc_client_data *cli = cccam->client; while (cli && (cccam->clipfd.count<CCCAM_MAX_PFD)) { if ( !IS_DISABLED(cli->flags) && (cli->handle>0) && !(cli->flags&FLAG_WORKTHREAD) ) { cli->ipoll = cccam->clipfd.count; cccam->clipfd.pfd[cccam->clipfd.count].fd = cli->handle; cccam->clipfd.pfd[cccam->clipfd.count++].events = POLLIN | POLLPRI; } else cli->ipoll = -1; cli = cli->next; } cccam->clipfd.update = 0; //debugf(getdbgflag(DBG_ERROR,0,0), " CCcam clients poll updated %d\n", cccam->clipfd.count); } cccam->clipfd.ipoll = pfdcount; if (cccam->clipfd.count>0) { memcpy( &pfd[pfdcount], cccam->clipfd.pfd, cccam->clipfd.count * sizeof(struct pollfd) ); pfdcount += cccam->clipfd.count; } } cccam = cccam->next; } int retval = poll(pfd, pfdcount, 3004); // for 3seconds if ( retval>0 ) { usleep(cfg.delay.thread); struct cccam_server_data *cccam = cfg.cccam.server; while (cccam) { if ( !IS_DISABLED(cccam->flags)&&(cccam->handle>0)&&(cccam->clipfd.count>0) ) { //pthread_mutex_lock(&prg.lockcccli); struct cc_client_data *cccli = cccam->client; while (cccli) { if ( !IS_DISABLED(cccli->flags)&&(cccli->handle>0)&&(cccli->ipoll>=0)&&(cccli->handle==pfd[cccam->clipfd.ipoll+cccli->ipoll].fd) ) { if ( pfd[cccam->clipfd.ipoll+cccli->ipoll].revents & (POLLHUP|POLLNVAL) ) cc_disconnect_cli(cccli); else if ( pfd[cccam->clipfd.ipoll+cccli->ipoll].revents & (POLLIN|POLLPRI) ) { cc_cli_recvmsg(cccli); } ///else if ( (GetTickCount()-cccli->lastactivity) > 600000 ) cc_disconnect_cli(cccli); } cccli = cccli->next; } //pthread_mutex_unlock(&prg.lockcccli); } cccam = cccam->next; } // if ( pfd[0].revents & (POLLIN|POLLPRI) ) cc_recv_pipe(); } else if ( retval<0 ) { debugf(getdbgflag(DBG_CCCAM,0,0), " thread receive messages: poll error %d(errno=%d)\n", retval, errno); usleep(99000); } } return NULL; } #endif /////////////////////////////////////////////////////////////////////////////// // CCCAM SERVER: START/STOP /////////////////////////////////////////////////////////////////////////////// int start_thread_cccam() { pthread_t tid; #ifndef MONOTHREAD_ACCEPT create_thread(&tid, cccam_accept_thread,NULL); #endif create_thread(&cfg.cccam.tid_recvmsg, cc_recvmsg_thread,NULL); return 0; }