Esempio n. 1
0
static void sort_ecmrl(struct s_reader *reader)
{
	int32_t i, j, loc;
	struct ecmrl tmp;

	for(i = 0; i < reader->ratelimitecm; i++)   // inspect all slots
	{
		if(reader->rlecmh[i].last.time == -1) { continue; }  // skip empty slots
		loc = i;
		tmp = reader->rlecmh[i]; // tmp is ecm in slot to evaluate

		for(j = i + 1; j < MAXECMRATELIMIT; j++)   // inspect all slots above the slot to be inspected
		{
			if(reader->rlecmh[j].last.time == -1) { continue; }  // skip empty slots
			int32_t gone = comp_timeb(&reader->rlecmh[i].last, &tmp.last);
			if(gone > 0)   // is higher slot holding a younger ecmrequest?
			{
				loc = j; // found a younger one
				tmp = reader->rlecmh[j]; // copy the ecm in younger slot
			}
		}

		if(loc != i)   // Did we find a younger ecmrequest?
		{
			reader->rlecmh[loc] = reader->rlecmh[i]; // place older request in slot of younger one we found
			reader->rlecmh[i] = tmp; // place younger request in slot of older request
		}
	}

	// release all slots above ratelimit ecm
	for(i = reader->ratelimitecm; i < MAXECMRATELIMIT; i++)
	{
		reader->rlecmh[i].last.time = -1;
		reader->rlecmh[i].srvid = -1;
		reader->rlecmh[i].kindecm = 0;
		reader->rlecmh[i].once = 0;
	}

}
Esempio n. 2
0
void cs_log_int(uint16_t mask, int8_t lock __attribute__((unused)), const uchar *buf, int32_t n, const char *fmt, ...)
{
	if((mask & cs_dblevel) || !mask)
	{
		va_list params;

		int32_t dupl_header_len, repeated_line, i, len = 0;
		pthread_mutex_lock(&log_mutex);
		if(fmt)
		{
			va_start(params, fmt);
			len = get_log_header(1, log_txt);
			vsnprintf(log_txt + len, sizeof(log_txt) - len, fmt, params);
			va_end(params);
			if(cfg.logduplicatelines)
			{
				memcpy(last_log_txt, log_txt + len, LOG_BUF_SIZE);
				write_to_log_int(log_txt, len);
			}
			else
			{
				repeated_line = strcmp(last_log_txt, log_txt + len) == 0;
				if(last_log_duplicates > 0)
				{
					if(!cs_valid_time(&last_log_ts))  // Must be initialized once
						{ last_log_ts = log_ts; }
					// Report duplicated lines when the new log line is different
					// than the old or 60 seconds have passed.
					int32_t gone = comp_timeb(&log_ts, &last_log_ts);
					if(!repeated_line || gone >= 60*1000)
					{
						dupl_header_len = get_log_header(2, dupl);
						snprintf(dupl + dupl_header_len - 1, sizeof(dupl) - dupl_header_len, "--- Skipped %u duplicated log lines ---", last_log_duplicates);
						write_to_log_int(dupl, 0);
						last_log_duplicates = 0;
						last_log_ts = log_ts;
					}
				}
				if(!repeated_line)
				{
					memcpy(last_log_txt, log_txt + len, LOG_BUF_SIZE);
					write_to_log_int(log_txt, len);
				}
				else
				{
					last_log_duplicates++;
				}
			}
		}
		if(buf)
		{
			for(i = 0; i < n; i += 16)
			{
				len = get_log_header(0, log_txt);
				cs_hexdump(1, buf + i, (n - i > 16) ? 16 : n - i, log_txt + len, sizeof(log_txt) - len);
				write_to_log_int(log_txt, len);
			}
		}
		pthread_mutex_unlock(&log_mutex);
	}
}
Esempio n. 3
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
}
Esempio n. 4
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;
}
Esempio n. 5
0
void *work_thread(void *ptr)
{
	struct job_data *data = (struct job_data *)ptr;
	struct s_client *cl = data->cl;
	struct s_reader *reader = cl->reader;
	struct timeb start, end;  // start time poll, end time poll

	struct job_data tmp_data;
	struct pollfd pfd[1];

	pthread_setspecific(getclient, cl);
	cl->thread = pthread_self();
	cl->thread_active = 1;

	set_work_thread_name(data);

	struct s_module *module = get_module(cl);
	uint16_t bufsize = module->bufsize; //CCCam needs more than 1024bytes!
	if(!bufsize)
		{ bufsize = 1024; }

	uint8_t *mbuf;
	if(!cs_malloc(&mbuf, bufsize))
		{ return NULL; }
	cl->work_mbuf = mbuf; // Track locally allocated data, because some callback may call cs_exit/cs_disconect_client/pthread_exit and then mbuf would be leaked
	int32_t n = 0, rc = 0, i, idx, s;
	uint8_t dcw[16];
	int8_t restart_reader = 0;
	while(cl->thread_active)
	{
		cs_ftime(&start); // register start time
		while(cl->thread_active)
		{
			if(!cl || cl->kill || !is_valid_client(cl))
			{
				pthread_mutex_lock(&cl->thread_lock);
				cl->thread_active = 0;
				pthread_mutex_unlock(&cl->thread_lock);
				cs_debug_mask(D_TRACE, "ending thread (kill)");
				__free_job_data(cl, data);
				cl->work_mbuf = NULL; // Prevent free_client from freeing mbuf (->work_mbuf)
				free_client(cl);
				if(restart_reader)
					{ restart_cardreader(reader, 0); }
				NULLFREE(mbuf);
				pthread_exit(NULL);
				return NULL;
			}

			if(data && data->action != ACTION_READER_CHECK_HEALTH)
				{ cs_debug_mask(D_TRACE, "data from add_job action=%d client %c %s", data->action, cl->typ, username(cl)); }

			if(!data)
			{
				if(!cl->kill && cl->typ != 'r')
					{ client_check_status(cl); } // do not call for physical readers as this might cause an endless job loop
				pthread_mutex_lock(&cl->thread_lock);
				if(cl->joblist && ll_count(cl->joblist) > 0)
				{
					LL_ITER itr = ll_iter_create(cl->joblist);
					data = ll_iter_next_remove(&itr);
					if(data)
						{ set_work_thread_name(data); }
					//cs_debug_mask(D_TRACE, "start next job from list action=%d", data->action);
				}
				pthread_mutex_unlock(&cl->thread_lock);
			}

			if(!data)
			{
				/* for serial client cl->pfd is file descriptor for serial port not socket
				   for example: pfd=open("/dev/ttyUSB0"); */
				if(!cl->pfd || module->listenertype == LIS_SERIAL)
					{ break; }
				pfd[0].fd = cl->pfd;
				pfd[0].events = POLLIN | POLLPRI;

				pthread_mutex_lock(&cl->thread_lock);
				cl->thread_active = 2;
				pthread_mutex_unlock(&cl->thread_lock);
				rc = poll(pfd, 1, 3000);
				pthread_mutex_lock(&cl->thread_lock);
				cl->thread_active = 1;
				pthread_mutex_unlock(&cl->thread_lock);
				if(rc > 0)
				{
					cs_ftime(&end); // register end time
					cs_debug_mask(D_TRACE, "[OSCAM-WORK] new event %d occurred on fd %d after %"PRId64" ms inactivity", pfd[0].revents,
								  pfd[0].fd, comp_timeb(&end, &start));
					data = &tmp_data;
					data->ptr = NULL;
					cs_ftime(&start); // register start time for new poll next run

					if(reader)
						{ data->action = ACTION_READER_REMOTE; }
					else
					{
						if(cl->is_udp)
						{
							data->action = ACTION_CLIENT_UDP;
							data->ptr = mbuf;
							data->len = bufsize;
						}
						else
							{ data->action = ACTION_CLIENT_TCP; }
						if(pfd[0].revents & (POLLHUP | POLLNVAL | POLLERR))
							{ cl->kill = 1; }
					}
				}
			}

			if(!data)
				{ continue; }

			if(!reader && data->action < ACTION_CLIENT_FIRST)
			{
				__free_job_data(cl, data);
				break;
			}

			if(!data->action)
				{ break; }

			struct timeb actualtime;
			cs_ftime(&actualtime);
			int32_t gone = comp_timeb(&actualtime, &data->time);
			if(data != &tmp_data && gone > (int) cfg.ctimeout+1000)
			{
				cs_debug_mask(D_TRACE, "dropping client data for %s time %dms", username(cl), gone);
				__free_job_data(cl, data);
				continue;
			}

			if(data != &tmp_data)
				{ cl->work_job_data = data; } // Track the current job_data
			switch(data->action)
			{
			case ACTION_READER_IDLE:
				reader_do_idle(reader);
				break;
			case ACTION_READER_REMOTE:
				s = check_fd_for_data(cl->pfd);
				if(s == 0)  // no data, another thread already read from fd?
					{ break; }
				if(s < 0)
				{
					if(reader->ph.type == MOD_CONN_TCP)
						{ network_tcp_connection_close(reader, "disconnect"); }
					break;
				}
				rc = reader->ph.recv(cl, mbuf, bufsize);
				if(rc < 0)
				{
					if(reader->ph.type == MOD_CONN_TCP)
						{ network_tcp_connection_close(reader, "disconnect on receive"); }
					break;
				}
				cl->last = time(NULL); // *********************************** TO BE REPLACE BY CS_FTIME() LATER ****************
				idx = reader->ph.c_recv_chk(cl, dcw, &rc, mbuf, rc);
				if(idx < 0) { break; }  // no dcw received
				if(!idx) { idx = cl->last_idx; }
				reader->last_g = time(NULL); // *********************************** TO BE REPLACE BY CS_FTIME() LATER **************** // for reconnect timeout
				for(i = 0, n = 0; i < cfg.max_pending && n == 0; i++)
				{
					if(cl->ecmtask[i].idx == idx)
					{
						cl->pending--;
						casc_check_dcw(reader, i, rc, dcw);
						n++;
					}
				}
				break;
			case ACTION_READER_RESET:
				cardreader_do_reset(reader);
				break;
			case ACTION_READER_ECM_REQUEST:
				reader_get_ecm(reader, data->ptr);
				break;
			case ACTION_READER_EMM:
				reader_do_emm(reader, data->ptr);
				break;
			case ACTION_READER_CARDINFO:
				reader_do_card_info(reader);
				break;
			case ACTION_READER_INIT:
				if(!cl->init_done)
					{ reader_init(reader); }
				break;
			case ACTION_READER_RESTART:
				cl->kill = 1;
				restart_reader = 1;
				break;
			case ACTION_READER_RESET_FAST:
				reader->card_status = CARD_NEED_INIT;
				cardreader_do_reset(reader);
				break;
			case ACTION_READER_CHECK_HEALTH:
				cardreader_do_checkhealth(reader);
				break;
			case ACTION_READER_CAPMT_NOTIFY:
				if(reader->ph.c_capmt) { reader->ph.c_capmt(cl, data->ptr); }
				break;
			case ACTION_CLIENT_UDP:
				n = module->recv(cl, data->ptr, data->len);
				if(n < 0) { break; }
				module->s_handler(cl, data->ptr, n);
				break;
			case ACTION_CLIENT_TCP:
				s = check_fd_for_data(cl->pfd);
				if(s == 0)  // no data, another thread already read from fd?
					{ break; }
				if(s < 0)    // system error or fd wants to be closed
				{
					cl->kill = 1; // kill client on next run
					continue;
				}
				n = module->recv(cl, mbuf, bufsize);
				if(n < 0)
				{
					cl->kill = 1; // kill client on next run
					continue;
				}
				module->s_handler(cl, mbuf, n);
				break;
			case ACTION_CACHEEX_TIMEOUT:
#ifdef CS_CACHEEX
				cacheex_timeout(data->ptr);
#endif
				break;
			case ACTION_FALLBACK_TIMEOUT:
				fallback_timeout(data->ptr);
				break;
			case ACTION_CLIENT_TIMEOUT:
				ecm_timeout(data->ptr);
				break;
			case ACTION_ECM_ANSWER_READER:
				chk_dcw(data->ptr);
				break;
			case ACTION_ECM_ANSWER_CACHE:
				write_ecm_answer_fromcache(data->ptr);
				break;
			case ACTION_CLIENT_INIT:
				if(module->s_init)
					{ module->s_init(cl); }
				cl->is_udp = module->type == MOD_CONN_UDP;
				cl->init_done = 1;
				break;
			case ACTION_CLIENT_IDLE:
				if(module->s_idle)
					{ module->s_idle(cl); }
				else
				{
					cs_log("user %s reached %d sec idle limit.", username(cl), cfg.cmaxidle);
					cl->kill = 1;
				}
				break;
			case ACTION_CACHE_PUSH_OUT:
			{
#ifdef CS_CACHEEX
				ECM_REQUEST *er = data->ptr;
				int32_t res = 0, stats = -1;
				// cc-nodeid-list-check
				if(reader)
				{
					if(reader->ph.c_cache_push_chk && !reader->ph.c_cache_push_chk(cl, er))
						{ break; }
					res = reader->ph.c_cache_push(cl, er);
					stats = cacheex_add_stats(cl, er->caid, er->srvid, er->prid, 0);
				}
				else
				{
					if(module->c_cache_push_chk && !module->c_cache_push_chk(cl, er))
						{ break; }
					res = module->c_cache_push(cl, er);
				}
				debug_ecm(D_CACHEEX, "pushed ECM %s to %s res %d stats %d", buf, username(cl), res, stats);
				cl->cwcacheexpush++;
				if(cl->account)
					{ cl->account->cwcacheexpush++; }
				first_client->cwcacheexpush++;
#endif
				break;
			}
			case ACTION_CLIENT_KILL:
				cl->kill = 1;
				break;
			case ACTION_CLIENT_SEND_MSG:
			{
#ifdef MODULE_CCCAM
				struct s_clientmsg *clientmsg = (struct s_clientmsg *)data->ptr;
				cc_cmd_send(cl, clientmsg->msg, clientmsg->len, clientmsg->cmd);
#endif
				break;
			}
			} // switch

			__free_job_data(cl, data);
		}

		if(thread_pipe[1] && (mbuf[0] != 0x00))
		{
			cs_ddump_mask(D_TRACE, mbuf, 1, "[OSCAM-WORK] Write to pipe:");
			if(write(thread_pipe[1], mbuf, 1) == -1)    // wakeup client check
			{
				cs_debug_mask(D_TRACE, "[OSCAM-WORK] Writing to pipe failed (errno=%d %s)", errno, strerror(errno));
			}
		}

		// Check for some race condition where while we ended, another thread added a job
		pthread_mutex_lock(&cl->thread_lock);
		if(cl->joblist && ll_count(cl->joblist) > 0)
		{
			pthread_mutex_unlock(&cl->thread_lock);
			continue;
		}
		else
		{
			cl->thread_active = 0;
			pthread_mutex_unlock(&cl->thread_lock);
			break;
		}
	}
	cl->thread_active = 0;
	cl->work_mbuf = NULL; // Prevent free_client from freeing mbuf (->work_mbuf)
	NULLFREE(mbuf);
	pthread_exit(NULL);
	return NULL;
}
Esempio n. 6
0
void cleanup_cache(void){
	ECMHASH *ecmhash;
	CW *cw;
	struct s_pushclient *pc, *nxt;
	node *i,*i_next,*j,*j_next;

	struct timeb now;
	int32_t gone_first, gone_upd;


	pthread_rwlock_wrlock(&cache_lock);

	i = get_first_node_list(&ll_cache);
	while (i) {
	    i_next = i->next;
	    ecmhash = get_data_from_node(i);

	    cs_ftime(&now);
	    gone_first = comp_timeb(&now, &ecmhash->first_recv_time);
	    gone_upd = comp_timeb(&now, &ecmhash->upd_time);

    	if(ecmhash && gone_first<=(cfg.max_cache_time*1000)){ //not continue, useless check for nexts one!
    		break;
    	}

    	if(ecmhash && gone_upd>(cfg.max_cache_time*1000)){

    		j = get_first_node_list(&ecmhash->ll_cw);
    		while (j) {
    			j_next = j->next;

    			cw = get_data_from_node(j);
    			if(cw){
					pthread_rwlock_destroy(&cw->pushout_client_lock);
					pc = cw->pushout_client;
					cw->pushout_client=NULL;
					while (pc) {
						nxt = pc->next_push;
						NULLFREE(pc);
						pc = nxt;
					}

					remove_elem_list(&ecmhash->ll_cw, &cw->ll_node);
					remove_elem_hash_table(&ecmhash->ht_cw, &cw->ht_node);
					NULLFREE(cw);
    			}

				j = j_next;
    		}

    		deinitialize_hash_table(&ecmhash->ht_cw);
    		remove_elem_list(&ll_cache, &ecmhash->ll_node);
    		remove_elem_hash_table(&ht_cache, &ecmhash->ht_node);
	    NULLFREE(ecmhash);
    	}

	    i = i_next;
	}

	pthread_rwlock_unlock(&cache_lock);
}
Esempio n. 7
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
}
Esempio n. 8
0
static void process_clients(void)
{
	int32_t i, k, j, rc, pfdcount = 0;
	struct s_client *cl;
	struct s_reader *rdr;
	struct pollfd *pfd;
	struct s_client **cl_list;
	struct timeb start, end;  // start time poll, end time poll
	uint32_t cl_size = 0;

	uchar buf[10];

	if(pipe(thread_pipe) == -1)
	{
		printf("cannot create pipe, errno=%d\n", errno);
		exit(1);
	}

	cl_size = chk_resize_cllist(&pfd, &cl_list, 0, 100);

	pfd[pfdcount].fd = thread_pipe[0];
	pfd[pfdcount].events = POLLIN | POLLPRI;
	cl_list[pfdcount] = NULL;

	while(!exit_oscam)
	{
		pfdcount = 1;

		//connected tcp clients
		for(cl = first_client->next; cl; cl = cl->next)
		{
			if(cl->init_done && !cl->kill && cl->pfd && cl->typ == 'c' && !cl->is_udp)
			{
				if(cl->pfd && !cl->thread_active)
				{
					cl_size = chk_resize_cllist(&pfd, &cl_list, cl_size, pfdcount);
					cl_list[pfdcount] = cl;
					pfd[pfdcount].fd = cl->pfd;
					pfd[pfdcount++].events = POLLIN | POLLPRI;
				}
			}
			//reader:
			//TCP:
			//  - TCP socket must be connected
			//  - no active init thread
			//UDP:
			//  - connection status ignored
			//  - no active init thread
			rdr = cl->reader;
			if(rdr && cl->typ == 'p' && cl->init_done)
			{
				if(cl->pfd && !cl->thread_active && ((rdr->tcp_connected && rdr->ph.type == MOD_CONN_TCP) || (rdr->ph.type == MOD_CONN_UDP)))
				{
					cl_size = chk_resize_cllist(&pfd, &cl_list, cl_size, pfdcount);
					cl_list[pfdcount] = cl;
					pfd[pfdcount].fd = cl->pfd;
					pfd[pfdcount++].events = (POLLIN | POLLPRI);
				}
			}
		}

		//server (new tcp connections or udp messages)
		for(k = 0; k < CS_MAX_MOD; k++)
		{
			struct s_module *module = &modules[k];
			if((module->type & MOD_CONN_NET))
			{
				for(j = 0; j < module->ptab.nports; j++)
				{
					if(module->ptab.ports[j].fd)
					{
						cl_size = chk_resize_cllist(&pfd, &cl_list, cl_size, pfdcount);
						cl_list[pfdcount] = NULL;
						pfd[pfdcount].fd = module->ptab.ports[j].fd;
						pfd[pfdcount++].events = (POLLIN | POLLPRI);
					}
				}
			}
		}

		if(pfdcount >= 1024)
			{ cs_log("WARNING: too many users!"); }
		cs_ftime(&start); // register start time
		rc = poll(pfd, pfdcount, 5000);
		if(rc < 1) { continue; }
		cs_ftime(&end); // register end time

		for(i = 0; i < pfdcount && rc > 0; i++)
		{
			if(pfd[i].revents == 0) { continue; }  // skip sockets with no changes
			rc--; //event handled!
			cs_log_dbg(D_TRACE, "[OSCAM] new event %d occurred on fd %d after %"PRId64" ms inactivity", pfd[i].revents,
						  pfd[i].fd, comp_timeb(&end, &start));
			//clients
			cl = cl_list[i];
			if(cl && !is_valid_client(cl))
				{ continue; }

			if(pfd[i].fd == thread_pipe[0] && (pfd[i].revents & (POLLIN | POLLPRI)))
			{
				// a thread ended and cl->pfd should be added to pollfd list again (thread_active==0)
				int32_t len = read(thread_pipe[0], buf, sizeof(buf));
				if(len == -1)
				{
					cs_log_dbg(D_TRACE, "[OSCAM] Reading from pipe failed (errno=%d %s)", errno, strerror(errno));
				}
				cs_log_dump_dbg(D_TRACE, buf, len, "[OSCAM] Readed:");
				continue;
			}

			//clients
			// message on an open tcp connection
			if(cl && cl->init_done && cl->pfd && (cl->typ == 'c' || cl->typ == 'm'))
			{
				if(pfd[i].fd == cl->pfd && (pfd[i].revents & (POLLHUP | POLLNVAL | POLLERR)))
				{
					//client disconnects
					kill_thread(cl);
					continue;
				}
				if(pfd[i].fd == cl->pfd && (pfd[i].revents & (POLLIN | POLLPRI)))
				{
					add_job(cl, ACTION_CLIENT_TCP, NULL, 0);
				}
			}


			//reader
			// either an ecm answer, a keepalive or connection closed from a proxy
			// physical reader ('r') should never send data without request
			rdr = NULL;
			struct s_client *cl2 = NULL;
			if(cl && cl->typ == 'p')
			{
				rdr = cl->reader;
				if(rdr)
					{ cl2 = rdr->client; }
			}

			if(rdr && cl2 && cl2->init_done)
			{
				if(cl2->pfd && pfd[i].fd == cl2->pfd && (pfd[i].revents & (POLLHUP | POLLNVAL | POLLERR)))
				{
					//connection to remote proxy was closed
					//oscam should check for rdr->tcp_connected and reconnect on next ecm request sent to the proxy
					network_tcp_connection_close(rdr, "closed");
					rdr_log_dbg(rdr, D_READER, "connection closed");
				}
				if(cl2->pfd && pfd[i].fd == cl2->pfd && (pfd[i].revents & (POLLIN | POLLPRI)))
				{
					add_job(cl2, ACTION_READER_REMOTE, NULL, 0);
				}
			}


			//server sockets
			// new connection on a tcp listen socket or new message on udp listen socket
			if(!cl && (pfd[i].revents & (POLLIN | POLLPRI)))
			{
				for(k = 0; k < CS_MAX_MOD; k++)
				{
					struct s_module *module = &modules[k];
					if((module->type & MOD_CONN_NET))
					{
						for(j = 0; j < module->ptab.nports; j++)
						{
							if(module->ptab.ports[j].fd && module->ptab.ports[j].fd == pfd[i].fd)
							{
								accept_connection(module, k, j);
							}
						}
					}
				}
			}
		}
		cs_ftime(&start); // register start time for new poll next run
		first_client->last = time((time_t *)0);
	}
	NULLFREE(pfd);
	NULLFREE(cl_list);
	return;
}
Esempio n. 9
0
bool IO_Serial_Read(struct s_reader *reader, uint32_t delay, uint32_t timeout, uint32_t size, unsigned char *data)
{
	uint32_t count = 0;

	if(timeout == 0)   // General fix for readers not communicating timeout and delay
	{
		if(reader->read_timeout != 0) { timeout = reader->read_timeout; }
		else { timeout = 9990000; }   // hope 99990000 is long enough!
		rdr_debug_mask(reader, D_DEVICE, "Warning: read timeout 0 changed to %d us", timeout);
	}

	rdr_debug_mask(reader, D_DEVICE, "Read timeout %d us, read delay %d us, to read %d char(s), chunksize %d char(s)", timeout, delay, size, size);

#if defined(WITH_STAPI) || defined(__SH4__) //internal stapi and sh4 readers need special treatment as they don't respond correctly to poll and some sh4 boxes only can read 1 byte at once
	if(reader->typ == R_INTERNAL)
	{
		int32_t readed;
#if defined(WITH_STAPI)
		const uint32_t chunksize = INT_MAX;
#elif defined(__SH4__)
		const uint32_t chunksize = 1;
#endif
		struct timeb start, end;
		cs_ftime(&start);
		end = start;
		int64_t gone = 0;
		int32_t timeout_ms = timeout / 1000;
		readed = 0;

		while(gone < timeout_ms)
		{
			readed = read(reader->handle, &data[count], size - count >= chunksize ? chunksize : size - count);
			cs_ftime(&end);
			if(readed > 0)
			{
				count += readed;
				cs_ftime(&start); // Reset timer
				end = start;
			}
			gone = comp_timeb(&end, &start);
			if(count < size)
			{
				if(readed < (int32_t)chunksize) { cs_sleepus(1); }
				continue;
			}
			else { break; }
		}
		if(count < size)
		{
			rdr_ddump_mask(reader, D_DEVICE, data, count, "Receiving:");
			return ERROR;
		}
	}
	else
#endif  // read all chars at once for all other boxes
	{
		while(count < size)
		{
			int32_t readed = -1, errorcount = 0;
AGAIN:
			if(IO_Serial_WaitToRead(reader, delay, timeout))
			{
				rdr_debug_mask(reader, D_DEVICE, "Timeout in IO_Serial_WaitToRead, timeout=%d us", timeout);
				return ERROR;
			}

			while(readed < 0 && errorcount < 10)
			{
				readed = read(reader->handle, &data[count], size - count);
				if(readed < 0)
				{
					if(errno == EINTR) { continue; }  // try again in case of interrupt
					if(errno == EAGAIN) { goto AGAIN; }  //EAGAIN needs select procedure again
					rdr_log(reader, "ERROR: %s (errno=%d %s)", __func__, errno, strerror(errno));
					errorcount++;
				}
			}

			if(readed == 0)
			{
				rdr_ddump_mask(reader, D_DEVICE, data, count, "Receiving:");
				rdr_debug_mask(reader, D_DEVICE, "Received End of transmission");
				return ERROR;
			}
			count += readed;
		}
	}
	rdr_ddump_mask(reader, D_DEVICE, data, count, "Receiving:");
	return OK;
}
Esempio n. 10
0
static int32_t cs_check_v(IN_ADDR_T ip, int32_t port, int32_t add, char *info, int32_t acosc_penalty_duration)
{
	int32_t result = 0;
	bool acosc_enabled = false;

#ifdef CS_ANTICASC
	if(cfg.acosc_enabled)
		acosc_enabled = true;
#endif

	if(!(cfg.failbantime || acosc_enabled))
		{ return 0; }

	if(!cfg.v_list)
		{ cfg.v_list = ll_create("v_list"); }

	struct timeb (now);
	cs_ftime(&now);
	LL_ITER itr = ll_iter_create(cfg.v_list);
	V_BAN *v_ban_entry;
	int32_t ftime = cfg.failbantime * 60 * 1000;

	//run over all banned entries to do housekeeping:
	while((v_ban_entry = ll_iter_next(&itr)))
	{
		// housekeeping:
		int32_t gone = comp_timeb(&now, &v_ban_entry->v_time);
		if(((gone >= ftime) && !v_ban_entry->acosc_entry) || (v_ban_entry->acosc_entry && ((gone/1000) >= v_ban_entry->acosc_penalty_dur))) // entry out of time->remove
		{
			NULLFREE(v_ban_entry->info);
			ll_iter_remove_data(&itr);
			continue;
		}

		if(IP_EQUAL(ip, v_ban_entry->v_ip) && port == v_ban_entry->v_port)
		{
			result = 1;
			if(!info)
				{ info = v_ban_entry->info; }
			else if(!v_ban_entry->info)
			{
				v_ban_entry->info = cs_strdup(info);
			}

			if(!add)
			{
				if(v_ban_entry->v_count >= cfg.failbancount)
				{
					if(!v_ban_entry->acosc_entry)
                    	{ cs_debug_mask(D_TRACE, "failban: banned ip %s:%d - %d seconds left%s%s", cs_inet_ntoa(v_ban_entry->v_ip), v_ban_entry->v_port, (ftime - gone)/1000, info ? ", info: " : "", info ? info : ""); }
					else
						{ cs_debug_mask(D_TRACE, "failban: banned ip %s:%d - %d seconds left%s%s", cs_inet_ntoa(v_ban_entry->v_ip), v_ban_entry->v_port, (v_ban_entry->acosc_penalty_dur - (gone/1000)), info?", info: ":"", info?info:""); }

				}
				else
				{
					cs_debug_mask(D_TRACE, "failban: ip %s:%d chance %d of %d%s%s",
								  cs_inet_ntoa(v_ban_entry->v_ip), v_ban_entry->v_port,
								  v_ban_entry->v_count, cfg.failbancount, info ? ", info: " : "", info ? info : "");
					v_ban_entry->v_count++;
				}
			}
			else
			{
				cs_debug_mask(D_TRACE, "failban: banned ip %s:%d - already exist in list%s%s",
							  cs_inet_ntoa(v_ban_entry->v_ip), v_ban_entry->v_port, info ? ", info: " : "", info ? info : "");
			}
		}
	}

	if(add && !result)
	{
		if(cs_malloc(&v_ban_entry, sizeof(V_BAN)))
		{
			cs_ftime(&v_ban_entry->v_time);
			v_ban_entry->v_ip = ip;
			v_ban_entry->v_port = port;
			v_ban_entry->v_count = 1;
			v_ban_entry->acosc_entry = false;
			v_ban_entry->acosc_penalty_dur = 0;
			if(acosc_penalty_duration > 0)
			{
				v_ban_entry->v_count = cfg.failbancount +1; // set it to a higher level
				v_ban_entry->acosc_entry = true;
				v_ban_entry->acosc_penalty_dur = acosc_penalty_duration;
			}
			if(info)
				{ v_ban_entry->info = cs_strdup(info); }
			ll_iter_insert(&itr, v_ban_entry);
			cs_debug_mask(D_TRACE, "failban: ban ip %s:%d with timestamp %ld%s%s",
						  cs_inet_ntoa(v_ban_entry->v_ip), v_ban_entry->v_port, v_ban_entry->v_time.time,
						  info ? ", info: " : "", info ? info : "");
		}
	}

	return result;
}