Beispiel #1
0
int32_t cardreader_do_ecm(struct s_reader *reader, ECM_REQUEST *er, struct s_ecm_answer *ea)
{
	int32_t rc = -1;
	if((rc = cardreader_do_checkhealth(reader)))
	{
		rdr_debug_mask(reader, D_READER, "%s: cardreader_do_checkhealth returned rc=%d", __func__, rc);
		struct s_client *cl = reader->client;
		if(cl)
		{
			cl->last_srvid = er->srvid;
			cl->last_caid = er->caid;
			cl->last = time((time_t *)0);
		}

		if(reader->csystem.active && reader->csystem.do_ecm)
		{
			rc = reader->csystem.do_ecm(reader, er, ea);
			rdr_debug_mask(reader, D_READER, "%s: after csystem.do_ecm rc=%d", __func__, rc);
		}
		else
			{ rc = 0; }
	}
	rdr_debug_mask(reader, D_READER, "%s: ret rc=%d", __func__, rc);
	return (rc);
}
int32_t cardreader_do_emm(struct s_reader *reader, EMM_PACKET *ep)
{
  int32_t rc=-1;

  rc=cardreader_do_checkhealth(reader);
  if (rc) {
	if ((1<<(ep->emm[0] % 0x80)) & reader->b_nano)
		return 3;

	if (reader->csystem.active && reader->csystem.do_emm)
		rc=reader->csystem.do_emm(reader, ep);
	else
		rc=0;
  }
  return(rc);
}
Beispiel #3
0
int32_t cardreader_do_emm(struct s_reader *reader, EMM_PACKET *ep)
{
  int32_t rc=-1;

  rc=cardreader_do_checkhealth(reader);
  if (rc) {
	if ((1<<(ep->emm[0] % 0x80)) & reader->b_nano)
		return 3;

	if (reader->csystem.active && reader->csystem.do_emm)
		rc=reader->csystem.do_emm(reader, ep);
	else
		rc=0;
  }
  if (rc >0) reader->emm_last = time(NULL); // last time emm written is now!
  return(rc);
}
Beispiel #4
0
int32_t cardreader_do_emm(struct s_reader *reader, EMM_PACKET *ep)
{
	int32_t rc;
	if (reader->typ == R_SMART ) {  // check health does not work with new card status check but is actually not needed for emm.
	rc = 1;
	} else {
	rc = -1;
	rc = cardreader_do_checkhealth(reader);
	}
	if(rc)
	{
		if((1 << (ep->emm[0] % 0x80)) & reader->b_nano)
			{ return 3; }

		if(reader->csystem.active && reader->csystem.do_emm)
			{ rc = reader->csystem.do_emm(reader, ep); }
		else
			{ rc = 0; }
	}
	if(rc > 0) { cs_ftime(&reader->emm_last); }  // last time emm written is now!
	return (rc);
}
Beispiel #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;
}