static int32_t constcw_send_ecm(struct s_client *client, ECM_REQUEST *er, uchar *UNUSED(msgbuf)) { time_t t; struct s_reader *rdr = client->reader; uchar cw[16]; t = time(NULL); // Check if DCW exist in the files //cs_log("Searching ConstCW for ECM: %04X:%06X:%04X (%d)", er->caid, er->prid, er->srvid, er->l); if (constcw_analyse_file(er->caid, er->prid, er->srvid, cw)==0) { write_ecm_answer(rdr, er, E_NOTFOUND, (E1_READER<<4 | E2_SID), NULL, NULL); } else { write_ecm_answer(rdr, er, E_FOUND, 0, cw, NULL); } client->last = t; rdr->last_g = t; return(0); }
void cardreader_process_ecm(struct s_reader *reader, struct s_client *cl, ECM_REQUEST *er) { if (ecm_ratelimit_check(reader, er, 1) != OK) { rdr_debug_mask(reader, D_READER, "%s: ratelimit check failed.", __func__); return; // reader_mode = 1: checkout ratelimiter in reader mode so srvid can be replaced } cs_ddump_mask(D_ATR, er->ecm, er->ecmlen, "ecm:"); struct timeb tps, tpe; cs_ftime(&tps); struct s_ecm_answer ea; memset(&ea, 0, sizeof(struct s_ecm_answer)); int32_t rc = cardreader_do_ecm(reader, er, &ea); rdr_debug_mask(reader, D_READER, "%s: cardreader_do_ecm returned rc=%d (ERROR=%d)", __func__, rc, ERROR); ea.rc = E_FOUND; //default assume found ea.rcEx = 0; //no special flag if (rc == ERROR) { char buf[32]; rdr_debug_mask(reader, D_READER, "Error processing ecm for caid %04X, srvid %04X, servicename: %s", er->caid, er->srvid, get_servicename(cl, er->srvid, er->caid, buf)); ea.rc = E_NOTFOUND; ea.rcEx = 0; ICC_Async_DisplayMsg(reader, "Eer"); } if (rc == E_CORRUPT) { char buf[32]; rdr_debug_mask(reader, D_READER, "Error processing ecm for caid %04X, srvid %04X, servicename: %s", er->caid, er->srvid, get_servicename(cl, er->srvid, er->caid, buf)); ea.rc = E_NOTFOUND; ea.rcEx = E2_WRONG_CHKSUM; //flag it as wrong checksum memcpy (ea.msglog,"Invalid ecm type for card",25); } cs_ftime(&tpe); cl->lastecm=time((time_t*)0); char ecmd5[17*3]; cs_hexdump(0, er->ecmd5, 16, ecmd5, sizeof(ecmd5)); rdr_debug_mask(reader, D_READER, "ecm hash: %s real time: %ld ms", ecmd5, 1000 * (tpe.time - tps.time) + tpe.millitm - tps.millitm); write_ecm_answer(reader, er, ea.rc, ea.rcEx, ea.cw, ea.msglog); reader_post_process(reader); }
void cardreader_process_ecm(struct s_reader *reader, struct s_client *cl, ECM_REQUEST *er) { cs_log_dump_dbg(D_ATR, er->ecm, er->ecmlen, "ecm:"); struct timeb tps, tpe; struct s_ecm_answer ea; memset(&ea, 0, sizeof(struct s_ecm_answer)); cs_ftime(&tps); int32_t rc = cardreader_do_ecm(reader, er, &ea); cs_ftime(&tpe); rdr_log_dbg(reader, D_READER, "%s: cardreader_do_ecm returned rc=%d (ERROR=%d)", __func__, rc, ERROR); ea.rc = E_FOUND; //default assume found ea.rcEx = 0; //no special flag if(rc == ERROR) { char buf[CS_SERVICENAME_SIZE]; rdr_log_dbg(reader, D_READER, "Error processing ecm for caid %04X, provid %06X, srvid %04X, servicename: %s", er->caid, er->prid, er->srvid, get_servicename(cl, er->srvid, er->prid, er->caid, buf, sizeof(buf))); ea.rc = E_NOTFOUND; ea.rcEx = 0; ICC_Async_DisplayMsg(reader, "Eer"); } if(rc == E_CORRUPT) { char buf[CS_SERVICENAME_SIZE]; rdr_log_dbg(reader, D_READER, "Error processing ecm for caid %04X, provid %06X, srvid %04X, servicename: %s", er->caid, er->prid, er->srvid, get_servicename(cl, er->srvid, er->prid, er->caid, buf, sizeof(buf))); ea.rc = E_NOTFOUND; ea.rcEx = E2_WRONG_CHKSUM; //flag it as wrong checksum memcpy(ea.msglog, "Invalid ecm type for card", 25); } write_ecm_answer(reader, er, ea.rc, ea.rcEx, ea.cw, ea.msglog, ea.tier, &ea.cw_ex); cl->lastecm = time((time_t *)0); char ecmd5[17 * 3]; cs_hexdump(0, er->ecmd5, 16, ecmd5, sizeof(ecmd5)); rdr_log_dbg(reader, D_READER, "ecm hash: %s real time: %"PRId64" ms", ecmd5, comp_timeb(&tpe, &tps)); reader_post_process(reader); }
static int32_t ecm_ratelimit_findspace(struct s_reader *reader, ECM_REQUEST *er, struct ecmrl rl, int32_t reader_mode) { int32_t h, foundspace = -1; int32_t maxecms = MAXECMRATELIMIT; // init maxecms int32_t totalecms = 0; // init totalecms struct timeb actualtime; cs_ftime(&actualtime); for(h = 0; h < MAXECMRATELIMIT; h++) // release slots with srvid that are overtime, even if not called from reader module to maximize available slots! { if(reader->rlecmh[h].last.time == -1) { continue; } int32_t gone = comp_timeb(&actualtime, &reader->rlecmh[h].last); if( gone >= (reader->rlecmh[h].ratelimittime + reader->rlecmh[h].srvidholdtime) || gone < 0) // gone <0 fixup for bad systemtime on dvb receivers while changing transponders { cs_debug_mask(D_CLIENT, "ratelimiter srvid %04X released from slot #%d/%d of reader %s (%d>=%d ratelimit ms + %d ms srvidhold!)", reader->rlecmh[h].srvid, h + 1, MAXECMRATELIMIT, reader->label, gone, reader->rlecmh[h].ratelimittime, reader->rlecmh[h].srvidholdtime); reader->rlecmh[h].last.time = -1; reader->rlecmh[h].srvid = -1; reader->rlecmh[h].kindecm = 0; } if(reader->rlecmh[h].last.time == -1) { continue; } if(reader->rlecmh[h].ratelimitecm < maxecms) { maxecms = reader->rlecmh[h].ratelimitecm; } // we found a more critical ratelimit srvid totalecms++; } cs_debug_mask(D_CLIENT, "ratelimiter found total of %d srvid for reader %s most critical is limited to %d requests", totalecms, reader->label, maxecms); if(reader->cooldown[0] && reader->cooldownstate != 1) { maxecms = MAXECMRATELIMIT; } // dont apply ratelimits if cooldown isnt in use or not in effect for(h = 0; h < MAXECMRATELIMIT; h++) // check if srvid is already in a slot { if(reader->rlecmh[h].last.time == -1) { continue; } if(reader->rlecmh[h].srvid == er->srvid && reader->rlecmh[h].caid == rl.caid && reader->rlecmh[h].provid == rl.provid && (!reader->rlecmh[h].chid || (reader->rlecmh[h].chid == rl.chid))) { int32_t gone = comp_timeb(&actualtime, &reader->rlecmh[h].last); cs_debug_mask(D_CLIENT, "ratelimiter found srvid %04X for %d ms in slot #%d/%d of reader %s", er->srvid, gone, h + 1, MAXECMRATELIMIT, reader->label); // check ecmunique if enabled and ecmunique time is done if(reader_mode && reader->ecmunique) { gone = comp_timeb(&actualtime, &reader->rlecmh[h].last); if(gone < reader->ratelimittime) { if(memcmp(reader->rlecmh[h].ecmd5, er->ecmd5, CS_ECMSTORESIZE)) { if(er->ecm[0] == reader->rlecmh[h].kindecm) { char ecmd5[17 * 3]; cs_hexdump(0, reader->rlecmh[h].ecmd5, 16, ecmd5, sizeof(ecmd5)); cs_debug_mask(D_CLIENT, "ratelimiter ecm %s in this slot for next %d ms!", ecmd5, (int)(reader->rlecmh[h].ratelimittime - gone)); struct ecm_request_t *erold = NULL; if(!cs_malloc(&erold, sizeof(struct ecm_request_t))) { return -2; } memcpy(erold, er, sizeof(struct ecm_request_t)); // copy ecm all memcpy(erold->ecmd5, reader->rlecmh[h].ecmd5, CS_ECMSTORESIZE); // replace md5 hash struct ecm_request_t *ecm = NULL; ecm = check_cache(erold, erold->client); //CHECK IF FOUND ECM IN CACHE NULLFREE(erold); if(ecm) //found in cache { write_ecm_answer(reader, er, ecm->rc, ecm->rcEx, ecm->cw, NULL); } else { write_ecm_answer(reader, er, E_NOTFOUND, E2_RATELIMIT, NULL, "Ratelimiter: no slots free!"); } NULLFREE(ecm); return -2; } continue; } } if((er->ecm[0] == reader->rlecmh[h].kindecm) && (gone <= (reader->ratelimittime + reader->srvidholdtime))) { cs_debug_mask(D_CLIENT, "ratelimiter srvid %04X ecm type %s, only allowing %s for next %d ms in slot #%d/%d of reader %s -> skipping this slot!", reader->rlecmh[h].srvid, (reader->rlecmh[h].kindecm == 0x80 ? "even" : "odd"), (reader->rlecmh[h].kindecm == 0x80 ? "odd" : "even"), (int)(reader->rlecmh[h].ratelimittime + reader->rlecmh[h].srvidholdtime - gone), h + 1, maxecms, reader->label); continue; } } if(h > 0) { for(foundspace = 0; foundspace < h; foundspace++) // check for free lower slot { if(reader->rlecmh[foundspace].last.time == -1) { reader->rlecmh[foundspace] = reader->rlecmh[h]; // replace ecm request info reader->rlecmh[h].srvid = -1; reader->rlecmh[h].last.time = -1; if(foundspace < maxecms) { cs_debug_mask(D_CLIENT, "ratelimiter moved srvid %04X to slot #%d/%d of reader %s", er->srvid, foundspace + 1, maxecms, reader->label); return foundspace; // moving to lower free slot! } else { cs_debug_mask(D_CLIENT, "ratelimiter removed srvid %04X from slot #%d/%d of reader %s", er->srvid, foundspace + 1, maxecms, reader->label); reader->rlecmh[foundspace].last.time = -1; // free this slot since we are over ratelimit! return -1; // sorry, ratelimit! } } } } if(h < maxecms) // found but cant move to lower position! { return h; // return position if within ratelimits! } else { reader->rlecmh[h].last.time = -1; // free this slot since we are over ratelimit! cs_debug_mask(D_CLIENT, "ratelimiter removed srvid %04X from slot #%d/%d of reader %s", er->srvid, h + 1, maxecms, reader->label); return -1; // sorry, ratelimit! } } } // srvid not found in slots! if((reader->cooldown[0] && reader->cooldownstate == 1) || !reader->cooldown[0]) { ; // do we use cooldown at all, are we in cooldown fase? // we are in cooldown or no cooldown configured! if(totalecms + 1 > maxecms || totalecms + 1 > rl.ratelimitecm) // check if this channel fits in! { cs_debug_mask(D_CLIENT, "ratelimiter for reader %s has no free slots!", reader->label); return -1; } } else { maxecms = MAXECMRATELIMIT; // no limits right now! } for(h = 0; h < maxecms; h++) // check for free slot { if(reader->rlecmh[h].last.time == -1) { if(reader_mode) { cs_debug_mask(D_CLIENT, "ratelimiter added srvid %04X to slot #%d/%d of reader %s", er->srvid, h + 1, maxecms, reader->label); } return h; // free slot found -> assign it! } else { int32_t gone = comp_timeb(&actualtime, &reader->rlecmh[h].last); cs_debug_mask(D_CLIENT, "ratelimiter srvid %04X for %d ms present in slot #%d/%d of reader %s", reader->rlecmh[h].srvid, gone , h + 1, maxecms, reader->label); } //occupied slots } #ifdef HAVE_DVBAPI /* Overide ratelimit priority for dvbapi request */ foundspace = -1; int32_t gone = 0; if((cfg.dvbapi_enabled == 1) && streq(er->client->account->usr, cfg.dvbapi_usr)) { if(reader->lastdvbapirateoverride.time == 0) { // fixup for first run! gone = comp_timeb(&actualtime, &reader->lastdvbapirateoverride); } if(gone > reader->ratelimittime) { struct timeb minecmtime = actualtime; for(h = 0; h < MAXECMRATELIMIT; h++) { gone = comp_timeb(&minecmtime, &reader->rlecmh[h].last); if(gone > 0) { minecmtime = reader->rlecmh[h].last; foundspace = h; } } reader->lastdvbapirateoverride = actualtime; cs_debug_mask(D_CLIENT, "prioritizing DVBAPI user %s over other watching client", er->client->account->usr); cs_debug_mask(D_CLIENT, "ratelimiter forcing srvid %04X into slot #%d/%d of reader %s", er->srvid, foundspace + 1, maxecms, reader->label); return foundspace; } else cs_debug_mask(D_CLIENT, "DVBAPI User %s is switching too fast for ratelimit and can't be prioritized!", er->client->account->usr); } #endif return (-1); // no slot found }
int32_t ecm_ratelimit_check(struct s_reader *reader, ECM_REQUEST *er, int32_t reader_mode) // If reader_mode is 1, ECM_REQUEST need to be assigned to reader and slot. // Else just report if a free slot is available. { // No rate limit set if(!reader->ratelimitecm) { return OK; } int32_t foundspace = -1, h, maxslots = MAXECMRATELIMIT; //init slots to oscam global maximums struct ecmrl rl; struct timeb now; rl = get_ratelimit(er); if(rl.ratelimitecm > 0) { cs_debug_mask(D_CLIENT, "ratelimit found for CAID: %04X PROVID: %06X SRVID: %04X CHID: %04X maxecms: %d cycle: %d ms srvidhold: %d ms", rl.caid, rl.provid, rl.srvid, rl.chid, rl.ratelimitecm, rl.ratelimittime, rl.srvidholdtime); } else // nothing found: apply general reader limits { rl.ratelimitecm = reader->ratelimitecm; rl.ratelimittime = reader->ratelimittime; rl.srvidholdtime = reader->srvidholdtime; rl.caid = er->caid; rl.provid = er->prid; rl.chid = er->chid; rl.srvid = er->srvid; cs_debug_mask(D_CLIENT, "ratelimiter apply readerdefault for CAID: %04X PROVID: %06X SRVID: %04X CHID: %04X maxecms: %d cycle: %d ms srvidhold: %d ms", rl.caid, rl.provid, rl.srvid, rl.chid, rl.ratelimitecm, rl.ratelimittime, rl.srvidholdtime); } // Below this line: rate limit functionality. // No cooldown set if(!reader->cooldown[0]) { cs_debug_mask(D_CLIENT, "ratelimiter find a slot for srvid %04X on reader %s", er->srvid, reader->label); foundspace = ecm_ratelimit_findspace(reader, er, rl, reader_mode); if(foundspace < 0) { if(reader_mode) { if(foundspace != -2) { cs_debug_mask(D_CLIENT, "ratelimiter no free slot for srvid %04X on reader %s -> dropping!", er->srvid, reader->label); write_ecm_answer(reader, er, E_NOTFOUND, E2_RATELIMIT, NULL, "Ratelimiter: no slots free!"); } } return ERROR; // not even trowing an error... obvious reason ;) } else //we are within ecmratelimits { if(reader_mode) { // Register new slot //reader->rlecmh[foundspace].srvid=er->srvid; // register srvid reader->rlecmh[foundspace] = rl; // register this srvid ratelimit params cs_ftime(&reader->rlecmh[foundspace].last); // register request time memcpy(reader->rlecmh[foundspace].ecmd5, er->ecmd5, CS_ECMSTORESIZE);// register ecmhash reader->rlecmh[foundspace].kindecm = er->ecm[0]; // register kind of ecm } return OK; } } // Below this line: rate limit functionality with cooldown option. // Cooldown state cycle: // state = 0: Cooldown setup phase. No rate limit set. // If number of ecm request exceed reader->ratelimitecm, cooldownstate goes to 2. // state = 2: Cooldown delay phase. No rate limit set. // If number of ecm request still exceed reader->ratelimitecm at end of cooldown delay phase, // cooldownstate goes to 1 (rate limit phase). // Else return back to setup phase (state 0). // state = 1: Cooldown ratelimit phase. Rate limit set. // If cooldowntime reader->cooldown[1] is elapsed, return to cooldown setup phase (state 0). cs_ftime(&now); int32_t gone = comp_timeb(&now, &reader->cooldowntime); if(reader->cooldownstate == 1) // Cooldown in ratelimit phase { if(gone <= reader->cooldown[1]*1000) // check if cooldowntime is elapsed { maxslots = reader->ratelimitecm; } // use user defined ratelimitecm else // Cooldown time is elapsed { reader->cooldownstate = 0; // set cooldown setup phase reader->cooldowntime.time = -1; // reset cooldowntime maxslots = MAXECMRATELIMIT; //use oscam defined max slots cs_log("Reader: %s ratelimiter returning to setup phase cooling down period of %d seconds is done!", reader->label, reader->cooldown[1]); } } // if cooldownstate == 1 if(reader->cooldownstate == 2 && gone > reader->cooldown[0]*1000) { // Need to check if the otherslots are not exceeding the ratelimit at the moment that // cooldown[0] time was exceeded! // time_t actualtime = reader->cooldowntime + reader->cooldown[0]; maxslots = 0; // maxslots is used as counter for(h = 0; h < MAXECMRATELIMIT; h++) { if(reader->rlecmh[h].last.time == -1) { continue; } // skip empty slots // how many active slots are registered at end of cooldown delay period gone = comp_timeb(&now, &reader->rlecmh[h].last); if(gone <= reader->ratelimittime) { maxslots++; if(maxslots >= reader->ratelimitecm) { break; } // Need to go cooling down phase } } if(maxslots < reader->ratelimitecm) { reader->cooldownstate = 0; // set cooldown setup phase reader->cooldowntime.time = -1; // reset cooldowntime maxslots = MAXECMRATELIMIT; // maxslots is maxslots again cs_log("Reader: %s ratelimiter returning to setup phase after %d seconds cooldowndelay!", reader->label, reader->cooldown[0]); } else { reader->cooldownstate = 1; // Entering ratelimit for cooldown ratelimitseconds cs_ftime(&reader->cooldowntime); // set time to enforce ecmratelimit for defined cooldowntime maxslots = reader->ratelimitecm; // maxslots is maxslots again sort_ecmrl(reader); // keep youngest ecm requests in list + housekeeping cs_log("Reader: %s ratelimiter starting cooling down period of %d seconds!", reader->label, reader->cooldown[1]); } } // if cooldownstate == 2 cs_debug_mask(D_CLIENT, "ratelimiter cooldownphase %d find a slot for srvid %04X on reader %s", reader->cooldownstate, er->srvid, reader->label); foundspace = ecm_ratelimit_findspace(reader, er, rl, reader_mode); if(foundspace < 0) { if(reader_mode) { if(foundspace != -2) { cs_debug_mask(D_CLIENT, "ratelimiter cooldownphase %d no free slot for srvid %04X on reader %s -> dropping!", reader->cooldownstate, er->srvid, reader->label); write_ecm_answer(reader, er, E_NOTFOUND, E2_RATELIMIT, NULL, "Ratelimiter: cooldown no slots free!"); } } return ERROR; // not even trowing an error... obvious reason ;) } else //we are within ecmratelimits { if(reader_mode) { // Register new slot //reader->rlecmh[foundspace].srvid=er->srvid; // register srvid reader->rlecmh[foundspace] = rl; // register this srvid ratelimit params cs_ftime(&reader->rlecmh[foundspace].last); // register request time memcpy(reader->rlecmh[foundspace].ecmd5, er->ecmd5, CS_ECMSTORESIZE);// register ecmhash reader->rlecmh[foundspace].kindecm = er->ecm[0]; // register kind of ecm } } if(reader->cooldownstate == 0 && foundspace >= reader->ratelimitecm) { if(!reader_mode) // No actual ecm request, just check { return OK; } cs_log("Reader: %s ratelimiter cooldown detected overrun ecmratelimit of %d during setup phase!", reader->label, (foundspace - reader->ratelimitecm + 1)); reader->cooldownstate = 2; // Entering cooldowndelay phase cs_ftime(&reader->cooldowntime); // Set cooldowntime to calculate delay cs_debug_mask(D_CLIENT, "ratelimiter cooldowndelaying %d seconds", reader->cooldown[0]); } // Cooldown state housekeeping is done. There is a slot available. if(reader_mode) { // Register new slot //reader->rlecmh[foundspace].srvid=er->srvid; // register srvid reader->rlecmh[foundspace] = rl; // register this srvid ratelimit params cs_ftime(&reader->rlecmh[foundspace].last); // register request time memcpy(reader->rlecmh[foundspace].ecmd5, er->ecmd5, CS_ECMSTORESIZE);// register ecmhash reader->rlecmh[foundspace].kindecm = er->ecm[0]; // register kind of ecm } return OK; }
static int32_t ecm_ratelimit_findspace(struct s_reader *reader, ECM_REQUEST *er, struct ecmrl rl, int32_t reader_mode) { int32_t h, foundspace = -1; int32_t maxecms = MAXECMRATELIMIT; // init maxecms int32_t totalecms = 0; // init totalecms struct timeb actualtime; cs_ftime(&actualtime); for(h = 0; h < MAXECMRATELIMIT; h++) // release slots with srvid that are overtime, even if not called from reader module to maximize available slots! { if(reader->rlecmh[h].last.time == -1) { continue; } int64_t gone = comp_timeb(&actualtime, &reader->rlecmh[h].last); if( gone >= (reader->rlecmh[h].ratelimittime + reader->rlecmh[h].srvidholdtime) || gone < 0) // gone <0 fixup for bad systemtime on dvb receivers while changing transponders { cs_log_dbg(D_CLIENT, "ratelimiter srvid %04X released from slot %d/%d of reader %s (%"PRId64">=%d ratelimit ms + %d ms srvidhold!)", reader->rlecmh[h].srvid, h + 1, MAXECMRATELIMIT, reader->label, gone, reader->rlecmh[h].ratelimittime, reader->rlecmh[h].srvidholdtime); reader->rlecmh[h].last.time = -1; reader->rlecmh[h].srvid = -1; reader->rlecmh[h].kindecm = 0; reader->rlecmh[h].once = 0; } if(reader->rlecmh[h].last.time == -1) { continue; } if(reader->rlecmh[h].ratelimitecm < maxecms) { maxecms = reader->rlecmh[h].ratelimitecm; } // we found a more critical ratelimit srvid totalecms++; } cs_log_dbg(D_CLIENT, "ratelimiter found total of %d srvid for reader %s most critical is limited to %d requests", totalecms, reader->label, maxecms); if(reader->cooldown[0] && reader->cooldownstate != 1) { maxecms = MAXECMRATELIMIT; } // dont apply ratelimits if cooldown isnt in use or not in effect for(h = 0; h < MAXECMRATELIMIT; h++) // check if srvid is already in a slot { if(reader->rlecmh[h].last.time == -1) { continue; } if(reader->rlecmh[h].srvid == er->srvid && reader->rlecmh[h].caid == rl.caid && reader->rlecmh[h].provid == rl.provid && (!reader->rlecmh[h].chid || (reader->rlecmh[h].chid == rl.chid))) { int64_t gone = comp_timeb(&actualtime, &reader->rlecmh[h].last); cs_log_dbg(D_CLIENT, "ratelimiter found srvid %04X for %"PRId64" ms in slot %d/%d of reader %s", er->srvid, gone, h + 1, MAXECMRATELIMIT, reader->label); // check ecmunique if enabled and ecmunique time is done if(reader_mode && reader->ecmunique) { gone = comp_timeb(&actualtime, &reader->rlecmh[h].last); if(gone < reader->ratelimittime) { if(memcmp(reader->rlecmh[h].ecmd5, er->ecmd5, CS_ECMSTORESIZE)) //some boxes seem to send different ecms but asking in fact for same cw! { // different ecm request than one in the slot! if(er->ecm[0] == reader->rlecmh[h].kindecm) { // same ecm type! char ecmd5[17 * 3]; cs_hexdump(0, reader->rlecmh[h].ecmd5, 16, ecmd5, sizeof(ecmd5)); cs_log_dbg(D_CLIENT, "ratelimiter ecm %s in this slot for next %d ms!", ecmd5, (int)(reader->rlecmh[h].ratelimittime - gone)); struct ecm_request_t *erold = NULL; if(!cs_malloc(&erold, sizeof(struct ecm_request_t))) { return -2; } memcpy(erold, er, sizeof(struct ecm_request_t)); // copy ecm all memcpy(erold->ecmd5, reader->rlecmh[h].ecmd5, CS_ECMSTORESIZE); // replace md5 hash struct ecm_request_t *ecm = NULL; ecm = check_cache(erold, erold->client); //CHECK IF FOUND ECM IN CACHE NULLFREE(erold); if(ecm) //found in cache { write_ecm_answer(reader, er, ecm->rc, ecm->rcEx, ecm->cw, NULL, 0, &ecm->cw_ex); } // return controlword of the ecm sitting in the slot! else { write_ecm_answer(reader, er, E_NOTFOUND, E2_RATELIMIT, NULL, "Ratelimiter: no slots free!", 0, NULL); } NULLFREE(ecm); return -2; } } } if((er->ecm[0] != reader->rlecmh[h].kindecm) && (gone <= reader->ratelimittime)) { if(!reader->rlecmh[h].once) // 1 premature ecmtype change is allowed (useful right after zapping to a channel!) { reader->rlecmh[h].once = 1; cs_log_dbg(D_CLIENT, "ratelimiter changing slot %d srvid %04X ecmtype once from %s to %s!", h+1, er->srvid, (reader->rlecmh[h].kindecm == 0x80 ? "even":"odd"), (er->ecm[0] == 0x80 ? "even":"odd")); } else { cs_log_dbg(D_CLIENT, "ratelimiter srvid %04X only allowing ecmtype %s for next %d ms in slot %d/%d of reader %s -> skipping this slot!", reader->rlecmh[h].srvid, (reader->rlecmh[h].kindecm == 0x80 ? "even" : "odd"), (int)(reader->rlecmh[h].ratelimittime - gone), h + 1, maxecms, reader->label); continue; } } } if(h > 0) { for(foundspace = 0; foundspace < h; foundspace++) // check for free lower slot { if(reader->rlecmh[foundspace].last.time == -1) { reader->rlecmh[foundspace] = reader->rlecmh[h]; // replace ecm request info reader->rlecmh[h].last.time = -1; reader->rlecmh[h].srvid = -1; reader->rlecmh[h].kindecm = 0; reader->rlecmh[h].once = 0; if(foundspace < maxecms) { cs_log_dbg(D_CLIENT, "ratelimiter moved srvid %04X to slot %d/%d of reader %s", er->srvid, foundspace + 1, maxecms, reader->label); return foundspace; // moving to lower free slot! } else { cs_log_dbg(D_CLIENT, "ratelimiter removed srvid %04X from slot %d/%d of reader %s", er->srvid, foundspace + 1, maxecms, reader->label); reader->rlecmh[foundspace].last.time = -1; // free this slot since we are over ratelimit! return -1; // sorry, ratelimit! } } } } if(h < maxecms) // found but cant move to lower position! { return h; // return position if within ratelimits! } else { reader->rlecmh[h].last.time = -1; // free this slot since we are over ratelimit! reader->rlecmh[h].srvid = -1; reader->rlecmh[h].kindecm = 0; reader->rlecmh[h].once = 0; cs_log_dbg(D_CLIENT, "ratelimiter removed srvid %04X from slot %d/%d of reader %s", er->srvid, h + 1, maxecms, reader->label); return -1; // sorry, ratelimit! } } } // srvid not found in slots! // do we use cooldown at all, are we in cooldown fase? if((reader->cooldown[0] && reader->cooldownstate == 1) || !reader->cooldown[0]) { // we are in cooldown or no cooldown configured! if(totalecms + 1 > maxecms || totalecms + 1 > rl.ratelimitecm) // check if this channel fits in! { cs_log_dbg(D_CLIENT, "ratelimiter for reader %s has no free slots!", reader->label); return -1; } } else { maxecms = MAXECMRATELIMIT; // no limits right now! } for(h = 0; h < maxecms; h++) // check for free slot { if(reader->rlecmh[h].last.time == -1) { if(reader_mode) { cs_log_dbg(D_CLIENT, "ratelimiter added srvid %04X to slot %d/%d of reader %s", er->srvid, h + 1, maxecms, reader->label); } return h; // free slot found -> assign it! } else { int64_t gone = comp_timeb(&actualtime, &reader->rlecmh[h].last); cs_log_dbg(D_CLIENT, "ratelimiter srvid %04X for %"PRId64" ms present in slot %d/%d of reader %s", reader->rlecmh[h].srvid, gone , h + 1, maxecms, reader->label); } //occupied slots } foundspace = dvbapi_override_prio(reader, er, maxecms, &actualtime); if (foundspace > -1) return foundspace; return (-1); // no slot found }