Beispiel #1
0
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);
}
Beispiel #3
0
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);
}
Beispiel #4
0
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
}
Beispiel #5
0
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;
}
Beispiel #6
0
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
}