Example #1
0
void config_list_set_defaults(const struct config_list *clist, void *config_data) {
	const struct config_list *c;
	for (c = clist; c->opt_type != OPT_UNKNOWN; c++) {
		void *var = config_data + c->var_offset;
		switch (c->opt_type) {
		case OPT_INT8: {
			*(int8_t *)var = c->def.d_int8;
			break;
		}
		case OPT_UINT8: {
			*(uint8_t *)var = c->def.d_uint8;
			break;
		}
		case OPT_INT32: {
			*(int32_t *)var = c->def.d_int32;
			break;
		}
		case OPT_UINT32: {
			*(uint32_t *)var = c->def.d_uint32;
			break;
		}
		case OPT_STRING: {
			char **scfg = var;
			NULLFREE(*scfg);
			if (c->def.d_char)
				*scfg = cs_strdup(c->def.d_char);
			break;
		}
		case OPT_SSTRING: {
			char *scfg = var;
			scfg[0] = '\0';
			if (c->def.d_char && strlen(c->def.d_char))
				cs_strncpy(scfg, c->def.d_char, c->str_size - 1);
			break;
		}
		case OPT_FUNC: {
			c->ops.process_fn((const char *)c->config_name, "", var, NULL);
			break;
		}
		case OPT_FUNC_EXTRA: {
			c->ops.process_fn_extra((const char *)c->config_name, "", var, c->def.d_extra, NULL);
			break;
		}
		case OPT_SAVE_FUNC:
		case OPT_FIXUP_FUNC:
		case OPT_UNKNOWN:
			continue;
		}
	}
	return;
}
Example #2
0
static void logfile_fn(const char *token, char *value, void *UNUSED(setting), FILE *f)
{
	if(value)
	{
		char *saveptr1 = NULL;
		cfg.logtostdout = 0;
		cfg.logtosyslog = 0;
		NULLFREE(cfg.logfile);
		if(strlen(value) > 0)
		{
			char *pch;
			for(pch = strtok_r(value, ";", &saveptr1); pch != NULL; pch = strtok_r(NULL, ";", &saveptr1))
			{
				pch = trim(pch);
				if(!strcmp(pch, "stdout")) { cfg.logtostdout = 1; }
				else if(!strcmp(pch, "syslog")) { cfg.logtosyslog = 1; }
				else
				{
					NULLFREE(cfg.logfile);
					if(!(cfg.logfile = cs_strdup(pch)))
						{ continue; }
				}
			}
		}
		else
		{
			if(!(cfg.logfile = cs_strdup(CS_LOGFILE)))
				{ cfg.logtostdout = 1; }
		}
		return;
	}
	if(cfg.logfile || cfg.logtostdout == 1 || cfg.logtosyslog == 1 || cfg.http_full_cfg)
	{
		value = mk_t_logfile();
		fprintf_conf(f, token, "%s\n", value);
		free_mk_t(value);
	}
}
Example #3
0
/*
 * Destroy the window specified and recycle the window slot.
 */
void nds_destroy_nhwindow(winid win)
{
  nds_nhwindow_t *window = windows[win];

  nds_clear_nhwindow(win);

  if (window->img) {
    free_ppm(window->img);
  }

  NULLFREE(window);

  windows[win] = NULL;
}
Example #4
0
void config_list_free_values(const struct config_list *clist, void *config_data) {
	const struct config_list *c;
	for (c = clist; c->opt_type != OPT_UNKNOWN; c++) {
		void *var = config_data + c->var_offset;
		if (c->opt_type == OPT_STRING) {
			char **scfg = var;
			NULLFREE(*scfg);
		}
		if (c->free_value && (c->opt_type == OPT_FUNC || c->opt_type == OPT_FUNC_EXTRA)) {
			c->free_value(var);
		}
	}
	return;
}
Example #5
0
void kill_all_clients(void)
{
	struct s_client *cl;
	for(cl = first_client->next; cl; cl = cl->next)
	{
		if(cl->typ == 'c' || cl->typ == 'm')
		{
			if(cl->account && cl->account->usr)
				{ cs_log("killing client %s", cl->account->usr); }
			kill_thread(cl);
		}
	}
	NULLFREE(processUsername);
}
Example #6
0
void cacheex_load_config_file(void)
{
    struct s_cacheex_matcher *entry, *old_list;

    old_list = cfg.cacheex_matcher;
    cfg.cacheex_matcher = cacheex_matcher_read_int();

    while(old_list)
    {
        entry = old_list->next;
        NULLFREE(old_list);
        old_list = entry;
    }
}
Example #7
0
int32_t ICC_Async_Device_Init (struct s_reader *reader)
{
	reader->fdmc=-1;
	rdr_debug_mask(reader, D_IFD, "Opening device %s", reader->device);
	reader->written = 0;
	int32_t ret = reader->crdr.reader_init(reader);
	if (ret == OK)
		rdr_debug_mask(reader, D_IFD, "Device %s succesfully opened", reader->device);
	else {
		if(reader->typ != R_SC8in1) NULLFREE(reader->crdr_data);
		rdr_debug_mask(reader, D_IFD, "ERROR: Can't open %s device", reader->device);
	}
	return ret;
}
Example #8
0
/* Clears the s_ptab struct provided by setting nfilts and nprids to zero. */
void clear_ptab(struct s_ptab *ptab)
{
	int32_t i;
	ptab->nports = 0;
	for(i = 0; i < CS_MAXPORTS; i++)
	{
		if(ptab->ports[i].ncd)
		{
			ptab->ports[i].ncd->ncd_ftab.nfilts = 0;
			ptab->ports[i].ncd->ncd_ftab.filts[0].nprids = 0;
			NULLFREE(ptab->ports[i].ncd);
			ptab->ports[i].ncd = NULL;
		}
	}
}
Example #9
0
nds_cmd_t nds_get_pan_direction()
{
  winid win;
  menu_item *sel;
  ANY_P ids[4];
  nds_cmd_t cmd;
  int res;

  win = create_nhwindow(NHW_MENU);
  start_menu(win);

  ids[0].a_int = CMD_PAN_UP;
  ids[1].a_int = CMD_PAN_DOWN;
  ids[2].a_int = CMD_PAN_LEFT;
  ids[3].a_int = CMD_PAN_RIGHT;

  add_menu(win, NO_GLYPH, &(ids[0]), 0, 0, 0, "Pan Up", 0);
  add_menu(win, NO_GLYPH, &(ids[1]), 0, 0, 0, "Pan Down", 0);
  add_menu(win, NO_GLYPH, &(ids[2]), 0, 0, 0, "Pan Left", 0);
  add_menu(win, NO_GLYPH, &(ids[3]), 0, 0, 0, "Pan Right", 0);

  end_menu(win, "What Direction?");
  res = select_menu(win, PICK_ONE, &sel);
  destroy_nhwindow(win);

  if (res <= 0) {
    cmd.f_char = -1;
    cmd.name = NULL;
  } else {
    cmd.f_char = sel->item.a_int;

    if (cmd.f_char == CMD_PAN_UP) {
      cmd.name = "Pan Up";
    } else if (cmd.f_char == CMD_PAN_DOWN) {
      cmd.name = "Pan Down";
    } else if (cmd.f_char == CMD_PAN_LEFT) {
      cmd.name = "Pan Left";
    } else if (cmd.f_char == CMD_PAN_RIGHT) {
      cmd.name = "Pan Right";
    }
  }

  NULLFREE(sel);

  return cmd;
}
Example #10
0
static struct CRYPTO_dynlock_value *SSL_dyn_create_function(const char *file, int32_t line)
{
	struct CRYPTO_dynlock_value *l;
	if(!cs_malloc(&l, sizeof(struct CRYPTO_dynlock_value)))
		{ return NULL; }

	if(pthread_mutex_init(&l->mutex, NULL))
	{
		// Initialization of mutex failed.
		NULLFREE(l);
		return (NULL);
	}
	pthread_mutex_init(&l->mutex, NULL);
	// just to remove compiler warnings...
	if(file || line) { return l; }
	return l;
}
Example #11
0
static int32_t radegast_send_ecm(struct s_client *client, ECM_REQUEST *er, uchar *UNUSED(buf))
{
	int32_t n;
	uchar provid_buf[8];
	uchar header[22] = "\x02\x01\x00\x06\x08\x30\x30\x30\x30\x30\x30\x30\x30\x07\x04\x30\x30\x30\x38\x08\x01\x02";
	uchar *ecmbuf;

	if(!radegast_connect())
		{ return (-1); }

	if(!cs_malloc(&ecmbuf, er->ecmlen + 30))
		{ return -1; }

	ecmbuf[0] = 1;
	ecmbuf[1] = (er->ecmlen + 30 - 2) & 0xff;
	memcpy(ecmbuf + 2, header, sizeof(header));
	for(n = 0; n < 4; n++)
	{
		snprintf((char *)provid_buf + (n * 2), sizeof(provid_buf) - (n * 2), "%02X", ((uchar *)(&er->prid))[4 - 1 - n]);
	}
	ecmbuf[7] = provid_buf[0];
	ecmbuf[8] = provid_buf[1];
	ecmbuf[9] = provid_buf[2];
	ecmbuf[10] = provid_buf[3];
	ecmbuf[11] = provid_buf[4];
	ecmbuf[12] = provid_buf[5];
	ecmbuf[13] = provid_buf[6];
	ecmbuf[14] = provid_buf[7];
	ecmbuf[2 + sizeof(header)] = 0xa;
	ecmbuf[3 + sizeof(header)] = 2;
	ecmbuf[4 + sizeof(header)] = er->caid >> 8;
	ecmbuf[5 + sizeof(header)] = er->caid & 0xff;
	ecmbuf[6 + sizeof(header)] = 3;
	ecmbuf[7 + sizeof(header)] = er->ecmlen & 0xff;
	memcpy(ecmbuf + 8 + sizeof(header), er->ecm, er->ecmlen);
	ecmbuf[4] = er->caid >> 8;

	client->reader->msg_idx = er->idx;
	n = send(client->pfd, ecmbuf, er->ecmlen + 30, 0);

	cs_debug_mask(D_TRACE, "radegast: sending ecm");
	cs_ddump_mask(D_CLIENT, ecmbuf, er->ecmlen + 30, "ecm:");
	NULLFREE(ecmbuf);
	return ((n < 1) ? (-1) : 0);
}
Example #12
0
static void scam_generate_deskey(char *keyString, uint8_t *desKey)
{
	uint8_t iv[8], *tmpKey;
	int32_t i, passLen, alignedPassLen;
	uint32_t key_schedule[32];
	
	memset(iv, 0, 8);
	memset(desKey, 0, 8);
	
	passLen = keyString == NULL ? 0 : strlen(keyString);
	if(passLen > 1024) {
		passLen = 1024;
	}

	alignedPassLen = (passLen + 7) & -8;
	if(alignedPassLen == 0) alignedPassLen = 8;
		
	if(!cs_malloc(&tmpKey, alignedPassLen)) {
		return;
	}

	if(passLen == 0) {
		memset(tmpKey, 0xAA, 8);
		passLen = 8;
	}
	else {
		memcpy(tmpKey, keyString, passLen);
	}
	
	for(i=0; i<alignedPassLen-passLen; i++) {
		tmpKey[passLen+i] = (uint8_t)i;
	}

	xxor(desKey,8,tmpKey,iv);	
	
	for(i=0; i<alignedPassLen; i+=8) {
		des_set_key(&tmpKey[i], key_schedule);
		des(&tmpKey[i], key_schedule, 1);
		xxor(desKey,8,desKey,&tmpKey[i]);
	}
	
	NULLFREE(tmpKey);
}
Example #13
0
void cacheex_cleanup_hitcache(bool force)
{
	CACHE_HIT *cachehit;
	node *i,*i_next;
	struct timeb now;
	int64_t gone, gone_max_hitcache_time;
	int32_t timeout = (cfg.max_hitcache_time + (cfg.max_hitcache_time / 2)) * 1000; // 1,5
	int32_t clean_grp = (cfg.max_hitcache_time * 1000);

	SAFE_RWLOCK_WRLOCK(&hitcache_lock);
	i = get_first_node_list(&ll_hitcache);
	while (i)
	{
		i_next = i->next;
		cachehit = get_data_from_node(i);

		if(!cachehit)
		{
			i = i_next;
			continue;
		}

		cs_ftime(&now);
		gone = comp_timeb(&now, &cachehit->time);
		gone_max_hitcache_time = comp_timeb(&now, &cachehit->max_hitcache_time);

		if(force || gone>timeout)
		{
			remove_elem_list(&ll_hitcache, &cachehit->ll_node);
			remove_elem_hash_table(&ht_hitcache, &cachehit->ht_node);
			NULLFREE(cachehit);
		}
		else if(gone_max_hitcache_time >= clean_grp){
			cachehit->grp = cachehit->grp_last_max_hitcache_time;
			cachehit->grp_last_max_hitcache_time = 0;
			cs_ftime(&cachehit->max_hitcache_time);
		}
		i = i_next;
	}
	SAFE_RWLOCK_UNLOCK(&hitcache_lock);
}
Example #14
0
void chk_cltab(char *classasc, CLASSTAB *clstab)
{
	int32_t max_an = 0, max_bn = 0;
	char *ptr1, *saveptr1 = NULL, *classasc_org;
	CLASSTAB newclstab, oldclstab;
	memset(&newclstab, 0, sizeof(newclstab));
	newclstab.an = newclstab.bn = 0;
	
	if(!cs_malloc(&classasc_org, sizeof(char)*strlen(classasc)+1))
		{ return; }
	
	cs_strncpy(classasc_org, classasc, sizeof(char)*strlen(classasc)+1);
	
	for(ptr1 = strtok_r(classasc, ",", &saveptr1); ptr1; ptr1 = strtok_r(NULL, ",", &saveptr1))
	{
		ptr1 = trim(ptr1);
		if(ptr1[0] == '!')
			{ max_bn++; }
		else
			{ max_an++; }
	}

	if(max_an && !cs_malloc(&newclstab.aclass, sizeof(uchar)*max_an))
		{ NULLFREE(classasc_org); return; }	

	if(max_bn && !cs_malloc(&newclstab.bclass, sizeof(uchar)*max_bn))
		{ NULLFREE(newclstab.aclass); NULLFREE(classasc_org); return; }	
	
	classasc = classasc_org;

	for(ptr1 = strtok_r(classasc, ",", &saveptr1); ptr1; ptr1 = strtok_r(NULL, ",", &saveptr1))
	{
		ptr1 = trim(ptr1);
		if(ptr1[0] == '!')
			{ newclstab.bclass[newclstab.bn++] = (uchar)a2i(ptr1 + 1, 2); }
		else
			{ newclstab.aclass[newclstab.an++] = (uchar)a2i(ptr1, 2); }
	}
	
	NULLFREE(classasc_org);
	
	memcpy(&oldclstab, clstab, sizeof(CLASSTAB));
	memcpy(clstab, &newclstab, sizeof(CLASSTAB));
	
	NULLFREE(oldclstab.aclass);
	NULLFREE(oldclstab.bclass);
}
Example #15
0
/****  INCOMING FILTER CHECK ***/
uint8_t check_cacheex_filter(struct s_client *cl, ECM_REQUEST *er)
{

	if(check_client(cl) && cl->typ == 'p' && cl->reader && cl->reader->cacheex.mode==2
			&& (!cl->reader->cacheex.drop_csp || checkECMD5(er))                              //cacheex_drop_csp-check
			&& chk_ctab(er->caid, &cl->reader->ctab)  			                              //Caid-check
			&& (!checkECMD5(er) || chk_ident_filter(er->caid, er->prid, &cl->reader->ftab))	  //Ident-check (not for csp: prid=0 always!)
			&& chk_srvid(cl, er) 								                              //Service-check
	  )
		{ return 1; }

	if(check_client(cl) && cl->typ == 'c' && cl->account && cl->account->cacheex.mode==3
			&& (!cl->account->cacheex.drop_csp || checkECMD5(er))                    //cacheex_drop_csp-check
			&& chk_ctab(er->caid, &cl->ctab)                                         //Caid-check
			&& (!checkECMD5(er) || chk_ident_filter(er->caid, er->prid, &cl->ftab))	 //Ident-check (not for csp: prid=0 always!)
			&& chk_srvid(cl, er)                                                     //Service-check
	  )
		{ return 1; }

	NULLFREE(er);
	return 0;
}
Example #16
0
static void cs_write_log_int(char *txt)
{
	if(exit_oscam == 1)
	{
		cs_write_log(txt, 1);
	}
	else
	{
		char *newtxt = cs_strdup(txt);
		if(!newtxt)
			{ return; }
		struct s_log *log;
		if(!cs_malloc(&log, sizeof(struct s_log)))
		{
			NULLFREE(newtxt);
			return;
		}
		log->txt = newtxt;
		log->header_len = 0;
		log->direct_log = 1;
		log_list_add(log);
	}
}
Example #17
0
int32_t cardreader_do_checkhealth(struct s_reader *reader)
{
	struct s_client *cl = reader->client;
	if(reader_card_inserted(reader))
	{
		if(reader->card_status == NO_CARD || reader->card_status == UNKNOWN)
		{
			rdr_log(reader, "card detected");
			led_status_card_detected();
			reader->card_status = CARD_NEED_INIT;
			add_job(cl, ACTION_READER_RESET, NULL, 0);
		}
	}
	else
	{
		rdr_log_dbg(reader, D_READER, "%s: !reader_card_inserted", __func__);
		if(reader->card_status == CARD_INSERTED || reader->card_status == CARD_NEED_INIT)
		{
			rdr_log(reader, "card ejected");
			reader_nullcard(reader);
			if(reader->csystem && reader->csystem->card_done)
				reader->csystem->card_done(reader);
			NULLFREE(reader->csystem_data);
			if(cl)
			{
				cl->lastemm = 0;
				cl->lastecm = 0;
			}
			led_status_card_ejected();
		}
		reader->card_status = NO_CARD;
	}
	rdr_log_dbg(reader, D_READER, "%s: reader->card_status = %d, ret = %d", __func__,
				   reader->card_status, reader->card_status == CARD_INSERTED);
	return reader->card_status == CARD_INSERTED;
}
Example #18
0
void cacheex_cwcheck_tab_fn(const char *token, char *value, void *setting, FILE *f)
{
	CWCHECKTAB *cacheex_value_table = setting;
	if(value)
	{
		if(strlen(value) == 0)
		{
			cacheex_value_table->cwchecknum = 0;
			NULLFREE(cacheex_value_table->cwcheckdata);
		}
		else
		{
			chk_cacheex_cwcheck_valuetab(value, cacheex_value_table);
		}
		return;
	}

	if(cacheex_value_table->cwchecknum || cfg.http_full_cfg)
	{
		value = mk_t_cacheex_cwcheck_valuetab(cacheex_value_table);
		fprintf_conf(f, token, "%s\n", value);
		free_mk_t(value);
	}
}
Example #19
0
int config_list_parse(const struct config_list *clist, const char *token, char *value, void *config_data)
{
	const struct config_list *c;
	for(c = clist; c->opt_type != OPT_UNKNOWN; c++)
	{
		if(c->opt_type == OPT_SAVE_FUNC || c->opt_type == OPT_FIXUP_FUNC)
			{ continue; }
		if(strcasecmp(token, c->config_name) != 0)
			{ continue; }
		void *var = config_data + c->var_offset;
		switch(c->opt_type)
		{
		case OPT_INT8:
		{
			*(int8_t *)var = (int8_t)strToIntVal(value, c->def.d_int8);
			return 1;
		}
		case OPT_UINT8:
		{
			uint32_t tmp = strToUIntVal(value, c->def.d_uint8);
			*(uint8_t *)var = (uint8_t)(tmp <= 0xff ? tmp : 0xff);
			return 1;
		}
		case OPT_INT32:
		{
			int32_t tmp = strToIntVal(value, c->def.d_int32);
			memcpy(var, &tmp, sizeof(int32_t));
			return 1;
		}
		case OPT_UINT32:
		{
			uint32_t tmp = strToUIntVal(value, c->def.d_uint32);
			memcpy(var, &tmp, sizeof(uint32_t));
			return 1;
		}
		case OPT_STRING:
		{
			char **scfg = var;
			if(c->def.d_char && strlen(value) == 0)  // Set default
				{ value = c->def.d_char; }
			NULLFREE(*scfg);
			if(strlen(value))
				{ *scfg = cs_strdup(value); }
			return 1;
		}
		case OPT_SSTRING:
		{
			char *scfg = var;
			if(c->def.d_char && strlen(value) == 0)  // Set default
				{ value = c->def.d_char; }
			scfg[0] = '\0';
			unsigned int len = strlen(value);
			if(len)
			{
				strncpy(scfg, value, c->str_size - 1);
				if(len > c->str_size)
				{
					fprintf(stderr, "WARNING: Config value for '%s' (%s, len=%u) exceeds max length: %d (%s)\n",
							token, value, len, c->str_size - 1, scfg);
				}
			}
			return 1;
		}
		case OPT_HEX_ARRAY:
		{
			uint8_t *hex_array = var;
			if(!strlen(value))
				{ memset(hex_array, 0, c->def.array_size); }
			else if(key_atob_l(value, hex_array, c->def.array_size * 2))
			{
				memset(hex_array, 0, c->def.array_size);
				fprintf(stderr, "WARNING: Config value for '%s' (%s, len=%zu) requires %d chars.\n",
						token, value, strlen(value), c->def.array_size * 2);
			}
			return 1;
		}
		case OPT_FUNC:
		{
			c->ops.process_fn(token, value, var, NULL);
			return 1;
		}
		case OPT_FUNC_EXTRA:
		{
			c->ops.process_fn_extra(token, value, var, c->def.d_extra, NULL);
			return 1;
		}
		case OPT_FIXUP_FUNC:
		case OPT_SAVE_FUNC:
			return 1;
		case OPT_UNKNOWN:
		{
			fprintf(stderr, "Unknown config type (%s = %s).", token, value);
			break;
		}
		}
	}
	return 0;
}
Example #20
0
static void *chkcache_process(void)
{
    set_thread_name(__func__);

    time_t timeout;
    struct ecm_request_t *er, *ecm;
#ifdef CS_CACHEEX
    uint8_t add_hitcache_er;
    struct s_reader *cl_rdr;
    struct s_reader *rdr;
    struct s_ecm_answer *ea;
    struct s_client *cex_src=NULL;
#endif
    struct s_write_from_cache *wfc=NULL;

    while(1)
    {
        cs_readlock(&ecmcache_lock);
        for(er = ecmcwcache; er; er = er->next)
        {
            timeout = time(NULL)-((cfg.ctimeout+500)/1000+1);
            if(er->tps.time < timeout)
            {
                break;
            }

            if(er->rc<E_UNHANDLED || er->readers_timeout_check)  //already answered
            {
                continue;
            }

            //********  CHECK IF FOUND ECM IN CACHE
            ecm = check_cache(er, er->client);
            if(ecm)     //found in cache
            {

#ifdef CS_CACHEEX
                //check for add_hitcache
                if(ecm->cacheex_src)   //cw from cacheex
                {
                    if((er->cacheex_wait_time && !er->cacheex_wait_time_expired) || !er->cacheex_wait_time)   //only when no wait_time expires (or not wait_time)
                    {

                        //add_hitcache already called, but we check if we have to call it for these (er) caid|prid|srvid
                        if(ecm->prid!=er->prid || ecm->srvid!=er->srvid)
                        {
                            cex_src = ecm->cacheex_src && is_valid_client(ecm->cacheex_src) && !ecm->cacheex_src->kill ?  ecm->cacheex_src : NULL; //here we should be sure cex client has not been freed!
                            if(cex_src) { //add_hitcache only if client is really active
                                add_hitcache_er=1;
                                cl_rdr = cex_src->reader;
                                if(cl_rdr && cl_rdr->cacheex.mode == 2)
                                {
                                    for(ea = er->matching_rdr; ea; ea = ea->next)
                                    {
                                        rdr = ea->reader;
                                        if(cl_rdr == rdr && ((ea->status & REQUEST_ANSWERED) == REQUEST_ANSWERED))
                                        {
                                            cs_debug_mask(D_CACHEEX|D_CSP|D_LB,"{client %s, caid %04X, prid %06X, srvid %04X} [CACHEEX] skip ADD self request!", (check_client(er->client)?er->client->account->usr:"******"),er->caid, er->prid, er->srvid);
                                            add_hitcache_er=0; //don't add hit cache, reader requested self
                                        }
                                    }
                                }

                                if(add_hitcache_er)
                                {
                                    add_hitcache(cex_src, er);    //USE cacheex client (to get correct group) and ecm from requesting client (to get correct caid|prid|srvid)!!!
                                }
                            }
                        }

                    }
                    else
                    {
                        //add_hitcache already called, but we have to remove it because cacheex not coming before wait_time
                        if(ecm->prid==er->prid && ecm->srvid==er->srvid)
                        {
                            del_hitcache(ecm);
                        }
                    }
                }
                //END check for add_hitcache
#endif

                if(check_client(er->client))
                {

                    wfc=NULL;
                    if(!cs_malloc(&wfc, sizeof(struct s_write_from_cache)))
                    {
                        NULLFREE(ecm);
                        continue;
                    }

                    wfc->er_new=er;
                    wfc->er_cache=ecm;

                    if(!add_job(er->client, ACTION_ECM_ANSWER_CACHE, wfc, sizeof(struct s_write_from_cache)))   //write_ecm_answer_fromcache
                    {
                        NULLFREE(ecm);
                        continue;
                    }
                }
                else
                {
                    NULLFREE(ecm);
                }
            }
        }
        cs_readunlock(&ecmcache_lock);

        cs_sleepms(10);
    }

    return NULL;
}
void dvbapi_load_channel_cache(void)
{
	if (USE_OPENXCAS) // Why?
		return;

	char fname[256];
	char line[1024];
	FILE *file;
	struct s_channel_cache *c;

	get_config_filename(fname, sizeof(fname), "oscam.ccache");
	file = fopen(fname, "r");
	if(!file)
	{
		cs_log("dvbapi channelcache can't read from file %s", fname);
		return;
	}

	int32_t i = 1;
	int32_t valid = 0;
	char *ptr, *saveptr1 = NULL;
	char *split[6];

	memset(line, 0, sizeof(line));
	while(fgets(line, sizeof(line), file))
	{
		if(!line[0] || line[0] == '#' || line[0] == ';')
			{ continue; }

		for(i = 0, ptr = strtok_r(line, ",", &saveptr1); ptr && i < 6 ; ptr = strtok_r(NULL, ",", &saveptr1), i++)
		{
			split[i] = ptr;
		}

		valid = (i == 5);
		if(valid)
		{
			if(!cs_malloc(&c, sizeof(struct s_channel_cache)))
			{ continue; }
			c->caid = a2i(split[0], 4);
			c->prid = a2i(split[1], 6);
			c->srvid = a2i(split[2], 4);
			c->pid = a2i(split[3], 4);
			c->chid = a2i(split[4], 6);

			if(valid && c->caid != 0)
			{
				if(!channel_cache)
				{
					channel_cache = ll_create("channel cache");
				}

				ll_append(channel_cache, c);
			}
			else
			{
				NULLFREE(c);
			}
		}
	}
	fclose(file);
	cs_log("dvbapi channelcache loaded from %s", fname);
}
Example #22
0
/*
 * mk_t-functions give back a constant empty string when allocation fails or when the result is an empty string.
 * This function thus checks the stringlength and only frees if necessary.
 */
void free_mk_t(char *value)
{
	if(strlen(value) > 0) { NULLFREE(value); }
}
void cc_cacheex_push_in(struct s_client *cl, uchar *buf)
{
	struct cc_data *cc = cl->cc;
	ECM_REQUEST *er;
	if(!cc) { return; }

	if(cl->reader)
		{ cl->reader->last_s = cl->reader->last_g = time((time_t *)0); }
	if(cl) { cl->last = time(NULL); }

	int8_t rc = buf[14];
	if(rc != E_FOUND && rc != E_UNHANDLED)  //Maybe later we could support other rcs
		{ return; }
	uint16_t size = buf[12] | (buf[13] << 8);
	if(size != sizeof(er->ecmd5) + sizeof(er->csp_hash) + sizeof(er->cw))
	{
		cs_log_dbg(D_CACHEEX, "cacheex: %s received old cash-push format! data ignored!", username(cl));
		return;
	}
	if(!(er = get_ecmtask()))
		{ return; }

	er->caid = b2i(2, buf + 0);
	er->prid = b2i(4, buf + 2);
	er->srvid = b2i(2, buf + 10);
	er->ecm[0] = buf[19]!=0x80 && buf[19]!=0x81 ? 0 : buf[19]; //odd/even byte, usefull to send it over CSP and to check cw for swapping
	er->rc = rc;

	er->ecmlen = 0;

	if(buf[18])
	{
		if(buf[18] & (0x01 << 7))
		{
			er->cwc_cycletime = (buf[18] & 0x7F); // remove bit 8 to get cycletime
			er->cwc_next_cw_cycle = 1;
		}
		else
		{
			er->cwc_cycletime = buf[18];
			er->cwc_next_cw_cycle = 0;
		}
	}

	if (er->cwc_cycletime && er->cwc_next_cw_cycle < 2)
	{
		if(cl->typ == 'c' && cl->account && cl->account->cacheex.mode)
			{ cl->account->cwc_info++; }
		else if((cl->typ == 'p' || cl->typ == 'r') && (cl->reader && cl->reader->cacheex.mode))
			{ cl->cwc_info++; }
		cs_log_dbg(D_CWC, "CWC (CE) received from %s cycletime: %isek - nextcwcycle: CW%i for %04X@%06X:%04X", username(cl), er->cwc_cycletime, er->cwc_next_cw_cycle, er->caid, er->prid, er->srvid);
	}

	uint8_t *ofs = buf + 20;

	//Read ecmd5
	memcpy(er->ecmd5, ofs, sizeof(er->ecmd5)); //16
	ofs += sizeof(er->ecmd5);

	if(!check_cacheex_filter(cl, er))
		{ return; }

	//Read csp_hash:
	er->csp_hash = ntohl(b2i(4, ofs));
	ofs += 4;

	//Read cw:
	memcpy(er->cw, ofs, sizeof(er->cw)); //16
	ofs += sizeof(er->cw);

	//Read lastnode count:
	uint8_t count = *ofs;
	ofs++;

	//check max nodes:
	if(count > cacheex_maxhop(cl))
	{
			cs_log_dbg(D_CACHEEX, "cacheex: received %d nodes (max=%d), ignored! %s", (int32_t)count, cacheex_maxhop(cl), username(cl));
		NULLFREE(er);
		return;
	}
	cs_log_dbg(D_CACHEEX, "cacheex: received %d nodes %s", (int32_t)count, username(cl));
	//Read lastnodes:
	uint8_t *data;
	if (er){
		er->csp_lastnodes = ll_create("csp_lastnodes");
	}
	while(count)
	{
		if(!cs_malloc(&data, 8))
			{ break; }
		memcpy(data, ofs, 8);
		ofs += 8;
		ll_append(er->csp_lastnodes, data);
		count--;
		cs_log_dbg(D_CACHEEX, "cacheex: received node %" PRIu64 "X %s", cacheex_node_id(data), username(cl));
	}

	//for compatibility: add peer node if no node received:
	if(!ll_count(er->csp_lastnodes))
	{
		if(!cs_malloc(&data, 8))
			{ return; }
		memcpy(data, cc->peer_node_id, 8);
		ll_append(er->csp_lastnodes, data);
		cs_log_dbg(D_CACHEEX, "cacheex: added missing remote node id %" PRIu64 "X", cacheex_node_id(data));
	}

	cacheex_add_to_cache(cl, er);
}
static int32_t cc_cacheex_push_out(struct s_client *cl, struct ecm_request_t *er)
{
	int8_t rc = (er->rc < E_NOTFOUND) ? E_FOUND : er->rc;
	if(rc != E_FOUND && rc != E_UNHANDLED) { return -1; }  //Maybe later we could support other rcs

	if(cl->reader)
	{
		if(!cl->reader->tcp_connected)
			{ cc_cli_connect(cl); }
	}

	struct cc_data *cc = cl->cc;
	if(!cc || !cl->udp_fd)
	{
		cs_log_dbg(D_CACHEEX, "cacheex: not connected %s -> no push", username(cl));
		return (-1);
	}

	uint32_t size = sizeof(er->ecmd5) + sizeof(er->csp_hash) + sizeof(er->cw) + sizeof(uint8_t) +
					(ll_count(er->csp_lastnodes) + 1) * 8;

	unsigned char *buf;
	if(!cs_malloc(&buf, size + 20))  //camd35_send() adds +20
		{ return -1; }

	// build ecm message
	//buf[0] = er->caid >> 8;
	//buf[1] = er->caid & 0xff;
	//buf[2] = er->prid >> 24;
	//buf[3] = er->prid >> 16;
	//buf[4] = er->prid >> 8;
	//buf[5] = er->prid & 0xff;
	//buf[10] = er->srvid >> 8;
	//buf[11] = er->srvid & 0xff;
	buf[12] = (sizeof(er->ecmd5) + sizeof(er->csp_hash) + sizeof(er->cw)) & 0xff;
	buf[13] = (sizeof(er->ecmd5) + sizeof(er->csp_hash) + sizeof(er->cw)) >> 8;
	//buf[12] = 0;
	//buf[13] = 0;
	buf[14] = rc;

	i2b_buf(2, er->caid, buf + 0);
	i2b_buf(4, er->prid, buf + 2);
	i2b_buf(2, er->srvid, buf + 10);

	if(er->cwc_cycletime && er->cwc_next_cw_cycle < 2)
	{
		buf[18] = er->cwc_cycletime; // contains cwc stage3 cycletime
		if(er->cwc_next_cw_cycle == 1)
		{ buf[18] = (buf[18] | 0x80); } // set bit 8 to high

		if(cl->typ == 'c' && cl->account && cl->account->cacheex.mode)
			{ cl->account->cwc_info++; }
		else if((cl->typ == 'p' || cl->typ == 'r') && (cl->reader && cl->reader->cacheex.mode))
			{ cl->cwc_info++; }
		cs_log_dbg(D_CWC, "CWC (CE) push to %s cycletime: %isek - nextcwcycle: CW%i for %04X@%06X:%04X", username(cl), er->cwc_cycletime, er->cwc_next_cw_cycle, er->caid, er->prid, er->srvid);
	}

	buf[19] = er->ecm[0] != 0x80 && er->ecm[0] != 0x81 ? 0 : er->ecm[0];

	uint8_t *ofs = buf + 20;

	//write oscam ecmd5:
	memcpy(ofs, er->ecmd5, sizeof(er->ecmd5)); //16
	ofs += sizeof(er->ecmd5);

	//write csp hashcode:
	i2b_buf(4, htonl(er->csp_hash), ofs);
	ofs += 4;

	//write cw:
	memcpy(ofs, er->cw, sizeof(er->cw)); //16
	ofs += sizeof(er->cw);

	//write node count:
	*ofs = ll_count(er->csp_lastnodes) + 1;
	ofs++;

	//write own node:
	memcpy(ofs, cc->node_id, 8);
	ofs += 8;

	//write other nodes:
	LL_LOCKITER *li = ll_li_create(er->csp_lastnodes, 0);
	uint8_t *node;
	while((node = ll_li_next(li)))
	{
		memcpy(ofs, node, 8);
		ofs += 8;
	}
	ll_li_destroy(li);

	int32_t res = cc_cmd_send(cl, buf, size + 20, MSG_CACHE_PUSH);
	if(res > 0)   // cache-ex is pushing out, so no receive but last_g should be updated otherwise disconnect!
	{
		if(cl->reader)
			{ cl->reader->last_s = cl->reader->last_g = time((time_t *)0); } // correct
		if(cl) { cl->last = time(NULL); }
	}
	NULLFREE(buf);
	return res;
}
Example #25
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
}
Example #26
0
static int32_t ghttp_recv_chk(struct s_client *client, uchar *dcw, int32_t *rc, uchar *buf, int32_t UNUSED(n))
{
  char* data;
  char* lenstr;
  int rcode, len = 0;
  s_ghttp* context = (s_ghttp*)client->ghttp;
  ECM_REQUEST *er = &context->last_ecm;

  data = strstr((char*)buf, "HTTP/1.1");
  if(!data) {
    cs_debug_mask(D_CLIENT, "%s: non http or otherwise corrupt response/disconnect: %s", client->reader->label, buf);     
    network_tcp_connection_close(client->reader, "receive error or idle timeout");
    return -1;
  }
  data = data + strlen("HTTP/1.1 ");
  rcode = atoi(data);
  if(rcode < 200 || rcode > 204) {
    cs_debug_mask(D_CLIENT, "%s: http error code %d", client->reader->label, rcode);    
    data = strstr(data, "Content-Type: application/octet-stream"); // if not octet-stream, google error. need reconnect?
    if(data) // we have error info string in data
    { 
      lenstr = strstr((char*)buf, "Content-Length: ");
      if(lenstr) {
        lenstr = lenstr + strlen("Content-Length: ");
        len = atoi(lenstr);
      }
      data = strstr(data, "\r\n\r\n") + 4;
      if(data) {
        data[len] = '\0';
        cs_debug_mask(D_CLIENT, "%s: http error message: %s", client->reader->label, data);
      }      
    }
    if(rcode == 503) {
      context->prev_sid = 0;
      if(context->do_post_next) {
        cs_debug_mask(D_CLIENT, "%s: recv_chk got 503 despite post, trying reconnect", client->reader->label);        
        network_tcp_connection_close(client->reader, "timeout");
        return -1;
      } else {
        // on 503 timeout, switch to POST
        context->do_post_next = 1;
        cs_debug_mask(D_CLIENT, "%s: recv_chk got 503, trying direct post", client->reader->label);         
        _ghttp_post_ecmdata(client, er);

        *rc = 0;
        memset(dcw, 0, 16);
        return -1;
      }
    } else if(rcode == 401) {
      cs_debug_mask(D_CLIENT, "%s: session expired, trying direct post", client->reader->label); 
      context->do_post_next = 1;
      NULLFREE(context->session_id);
      _ghttp_post_ecmdata(client, er);

      *rc = 0;
      memset(dcw, 0, 16);
      return -1;
    }
    return -1;
  }

  // switch back to cache get after rapid ecm response (arbitrary atm), only effect is a slight bw save for client
  if(context->do_post_next && context->last_ecm.srvid == context->prev_sid) {
    if(client->cwlastresptime > 0 && client->cwlastresptime < 800) {
      cs_debug_mask(D_CLIENT, "%s: prev resp time for same sid was %d ms, switching back to cache get for next req", client->reader->label, client->cwlastresptime); 
      context->do_post_next = 0;
    }
  }

  data = strstr((char*)buf, "Set-Cookie: GSSID=");
  if(data) {
    data += strlen("Set-Cookie: GSSID=");
    NULLFREE(context->session_id);
    if(cs_malloc(&context->session_id, 7)) { // todo dont assume session id of length 6
      strncpy((char*)context->session_id, data, 6);
      context->session_id[6] = '\0';
      cs_debug_mask(D_CLIENT, "%s: set session_id to: %s", client->reader->label, context->session_id);
    }
  }

  data = strstr((char*)buf, "Content-Length: 16");
  if(data) {
    data = strstr((char*)buf, "\r\n\r\n");
    data += 4;
    memcpy(dcw, data, 16);
    *rc = 1;
    char tmp_dbg[33];
    cs_debug_mask(D_CLIENT, "%s: recv chk - %s", client->reader->label, cs_hexdump(0, dcw, 16, tmp_dbg, sizeof (tmp_dbg)));
    return client->reader->msg_idx;
  } else {
    cs_debug_mask(D_CLIENT, "%s: recv_chk fail!", client->reader->label);
  }
  return -1;
}
Example #27
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;
}
Example #28
0
/**
 * adds a job to the job queue
 * if ptr should be free() after use, set len to the size
 * else set size to 0
**/
int32_t add_job(struct s_client *cl, enum actions action, void *ptr, int32_t len)
{
	if(!cl || cl->kill)
	{
		if(!cl)
			{ cs_log("WARNING: add_job failed. Client killed!"); } // Ignore jobs for killed clients
		if(len && ptr)
			{ NULLFREE(ptr); }
		return 0;
	}


#ifdef CS_CACHEEX
	// Avoid full running queues:
	if(action == ACTION_CACHE_PUSH_OUT && ll_count(cl->joblist) > 2000)
	{
		cs_debug_mask(D_TRACE, "WARNING: job queue %s %s has more than 2000 jobs! count=%d, dropped!",
					  cl->typ == 'c' ? "client" : "reader",
					  username(cl), ll_count(cl->joblist));
		if(len && ptr)
			{ NULLFREE(ptr); }
		// Thread down???
		pthread_mutex_lock(&cl->thread_lock);
		if(cl && !cl->kill && cl->thread && cl->thread_active)
		{
			// Just test for invalid thread id:
			if(pthread_detach(cl->thread) == ESRCH)
			{
				cl->thread_active = 0;
				cs_debug_mask(D_TRACE, "WARNING: %s %s thread died!",
							  cl->typ == 'c' ? "client" : "reader", username(cl));
			}
		}
		pthread_mutex_unlock(&cl->thread_lock);
		return 0;
	}
#endif


	struct job_data *data;
	if(!cs_malloc(&data, sizeof(struct job_data)))
	{
		if(len && ptr)
			{ NULLFREE(ptr); }
		return 0;
	}

	data->action = action;
	data->ptr    = ptr;
	data->cl     = cl;
	data->len    = len;
	cs_ftime(&data->time);

	pthread_mutex_lock(&cl->thread_lock);
	if(cl && !cl->kill && cl->thread_active)
	{
		if(!cl->joblist)
			{ cl->joblist = ll_create("joblist"); }
		ll_append(cl->joblist, data);
		if(cl->thread_active == 2)
			{ pthread_kill(cl->thread, OSCAM_SIGNAL_WAKEUP); }
		pthread_mutex_unlock(&cl->thread_lock);
		cs_debug_mask(D_TRACE, "add %s job action %d queue length %d %s",
					  action > ACTION_CLIENT_FIRST ? "client" : "reader", action,
					  ll_count(cl->joblist), username(cl));
		return 1;
	}

	pthread_attr_t attr;
	pthread_attr_init(&attr);
	/* pcsc doesn't like this either; segfaults on x86, x86_64 */
	struct s_reader *rdr = cl->reader;
	if(cl->typ != 'r' || !rdr || rdr->typ != R_PCSC)
		{ pthread_attr_setstacksize(&attr, PTHREAD_STACK_SIZE); }

	if(action != ACTION_READER_CHECK_HEALTH)
	{
		cs_debug_mask(D_TRACE, "start %s thread action %d",
					  action > ACTION_CLIENT_FIRST ? "client" : "reader", action);
	}

	int32_t ret = pthread_create(&cl->thread, &attr, work_thread, (void *)data);
	if(ret)
	{
		cs_log("ERROR: can't create thread for %s (errno=%d %s)",
			   action > ACTION_CLIENT_FIRST ? "client" : "reader", ret, strerror(ret));
		free_job_data(data);
	}
	else
	{
		pthread_detach(cl->thread);
	}
	pthread_attr_destroy(&attr);

	cl->thread_active = 1;
	pthread_mutex_unlock(&cl->thread_lock);
	return 1;
}
Example #29
0
int32_t init_srvid(void)
{
	int8_t new_syntax = 1;
	FILE *fp = open_config_file("oscam.srvid2");
	if(!fp)
	{ 
		fp = open_config_file(cs_srid);
		if(fp)
		{
			new_syntax = 0;
		}
	}

	if(!fp)
	{ 
		fp = create_config_file("oscam.srvid2");
		if(fp)
		{
			flush_config_file(fp, "oscam.srvid2");
		}
		
		return 0;
	}

	int32_t nr = 0, i, j;
	char *payload, *saveptr1 = NULL, *saveptr2 = NULL, *token;
	const char *tmp;
	if(!cs_malloc(&token, MAXLINESIZE))
		{ return 0; }
	struct s_srvid *srvid = NULL, *new_cfg_srvid[16], *last_srvid[16];
	// A cache for strings within srvids. A checksum is calculated which is the start point in the array (some kind of primitive hash algo).
	// From this point, a sequential search is done. This greatly reduces the amount of string comparisons.
	const char **stringcache[1024];
	int32_t allocated[1024] = { 0 };
	int32_t used[1024] = { 0 };
	struct timeb ts, te;
	cs_ftime(&ts);

	memset(last_srvid, 0, sizeof(last_srvid));
	memset(new_cfg_srvid, 0, sizeof(new_cfg_srvid));

	while(fgets(token, MAXLINESIZE, fp))
	{
		int32_t l, len = 0, len2, srvidtmp;
		uint32_t k;
		uint32_t pos;
		char *srvidasc, *prov;
		tmp = trim(token);

		if(tmp[0] == '#') { continue; }
		if((l = strlen(tmp)) < 6) { continue; }
		if(!(srvidasc = strchr(token, ':'))) { continue; }
		if(!(payload = strchr(token, '|'))) { continue; }
		*payload++ = '\0';
		
		if(!cs_malloc(&srvid, sizeof(struct s_srvid)))
		{
			NULLFREE(token);
			fclose(fp);
			return (1);
		}

		char tmptxt[128];

		int32_t offset[4] = { -1, -1, -1, -1 };
		char *ptr1 = NULL, *ptr2 = NULL;
		const char *searchptr[4] = { NULL, NULL, NULL, NULL };
		const char **ptrs[4] = { &srvid->prov, &srvid->name, &srvid->type, &srvid->desc };
		uint32_t max_payload_length = MAXLINESIZE - (payload - token);
		
		if(new_syntax)
		{
			ptrs[0] = &srvid->name;
			ptrs[1] = &srvid->type;
			ptrs[2] = &srvid->desc;
			ptrs[3] = &srvid->prov;
		}
		
		// allow empty strings as "||"
		if(payload[0] == '|' && (strlen(payload)+2 < max_payload_length))
		{
			memmove(payload+1, payload, strlen(payload)+1);
			payload[0] = ' ';
		}
		
		for(k=1; ((k < max_payload_length) && (payload[k] != '\0')); k++)
		{
			if(payload[k-1] == '|' && payload[k] == '|')
			{
				if(strlen(payload+k)+2 < max_payload_length-k)
				{
					memmove(payload+k+1, payload+k, strlen(payload+k)+1);
					payload[k] = ' ';
				}
				else
				{
					break;
				}	
			}
		}
	
		for(i = 0, ptr1 = strtok_r(payload, "|", &saveptr1); ptr1 && (i < 4) ; ptr1 = strtok_r(NULL, "|", &saveptr1), ++i)
		{
			// check if string is in cache
			len2 = strlen(ptr1);
			pos = 0;
			for(j = 0; j < len2; ++j) { pos += (uint8_t)ptr1[j]; }
			pos = pos % 1024;
			for(j = 0; j < used[pos]; ++j)
			{
				if(!strcmp(stringcache[pos][j], ptr1))
				{
					searchptr[i] = stringcache[pos][j];
					break;
				}
			}
			if(searchptr[i]) { continue; }

			offset[i] = len;
			cs_strncpy(tmptxt + len, trim(ptr1), sizeof(tmptxt) - len);
			len += strlen(ptr1) + 1;
		}

		char *tmpptr = NULL;
		if(len > 0 && !cs_malloc(&tmpptr, len))
			{ continue; }

		srvid->data = tmpptr;
		if(len > 0) { memcpy(tmpptr, tmptxt, len); }

		for(i = 0; i < 4; i++)
		{
			if(searchptr[i])
			{
				*ptrs[i] = searchptr[i];
				continue;
			}
			if(offset[i] > -1)
			{
				*ptrs[i] = tmpptr + offset[i];
				// store string in stringcache
				tmp = *ptrs[i];
				len2 = strlen(tmp);
				pos = 0;
				for(j = 0; j < len2; ++j) { pos += (uint8_t)tmp[j]; }
				pos = pos % 1024;
				if(used[pos] >= allocated[pos])
				{
					if(allocated[pos] == 0)
					{
						if(!cs_malloc(&stringcache[pos], 16 * sizeof(char *)))
							{ break; }
					}
					else
					{
						if(!cs_realloc(&stringcache[pos], (allocated[pos] + 16) * sizeof(char *)))
							{ break; }
					}
					allocated[pos] += 16;
				}
				stringcache[pos][used[pos]] = tmp;
				used[pos] += 1;
			}
		}

		*srvidasc++ = '\0';
		if(new_syntax)
			{ srvidtmp = dyn_word_atob(token) & 0xFFFF; }
		else
			{ srvidtmp = dyn_word_atob(srvidasc) & 0xFFFF; }
			
		if(srvidtmp < 0)
		{
			NULLFREE(tmpptr);
			NULLFREE(srvid);
			continue;
		}
		else
		{
			srvid->srvid = srvidtmp;
		}		
		
		srvid->ncaid = 0;
		for(i = 0, ptr1 = strtok_r(new_syntax ? srvidasc : token, ",", &saveptr1); (ptr1); ptr1 = strtok_r(NULL, ",", &saveptr1), i++)
		{
			srvid->ncaid++;
		}
		
		if(!cs_malloc(&srvid->caid, sizeof(struct s_srvid_caid) * srvid->ncaid))
		{
			NULLFREE(tmpptr);
			NULLFREE(srvid);
			return 0;
		}
		
		ptr1 = new_syntax ? srvidasc : token;
		for(i = 0; i < srvid->ncaid; i++)
		{
			prov = strchr(ptr1,'@');
						
			srvid->caid[i].nprovid = 0;
			
			if(prov)
			{
				if(prov[1] != '\0')
				{
					for(j = 0, ptr2 = strtok_r(prov+1, "@", &saveptr2); (ptr2); ptr2 = strtok_r(NULL, "@", &saveptr2), j++)
					{
						srvid->caid[i].nprovid++;
					}
		    		
					if(!cs_malloc(&srvid->caid[i].provid, sizeof(uint32_t) * srvid->caid[i].nprovid))
					{
						for(j = 0; j < i; j++)
							{ NULLFREE(srvid->caid[j].provid); } 
						NULLFREE(srvid->caid);
						NULLFREE(tmpptr);
						NULLFREE(srvid);
						return 0;
					}
					
					ptr2 = prov+1;
					for(j = 0;  j < srvid->caid[i].nprovid; j++)
					{
						srvid->caid[i].provid[j] = dyn_word_atob(ptr2) & 0xFFFFFF;
						ptr2 = ptr2 + strlen(ptr2) + 1;
					}
				}
				else
				{
					ptr2 = prov+2;
				}
				
				prov[0] = '\0';
			}

			srvid->caid[i].caid = dyn_word_atob(ptr1) & 0xFFFF;
			if(prov)
				{ ptr1 = ptr2; }
			else 
				{ ptr1 = ptr1 + strlen(ptr1) + 1; }
		}
			
		nr++;

		if(new_cfg_srvid[srvid->srvid >> 12])
			{ last_srvid[srvid->srvid >> 12]->next = srvid; }
		else
			{ new_cfg_srvid[srvid->srvid >> 12] = srvid; }

		last_srvid[srvid->srvid >> 12] = srvid;
	}
Example #30
0
int32_t init_provid(void)
{
	FILE *fp = open_config_file(cs_provid);
	if(!fp)
		{ return 0; }

	int32_t nr;
	char *payload, *saveptr1 = NULL, *token;
	if(!cs_malloc(&token, MAXLINESIZE))
		{ return 0; }
	struct s_provid *provid_ptr = NULL;
	struct s_provid *new_cfg_provid = NULL, *last_provid;

	nr = 0;
	while(fgets(token, MAXLINESIZE, fp))
	{
		int32_t i, l;
		struct s_provid *new_provid = NULL;
		char *tmp, *ptr1;
		
		tmp = trim(token);

		if(tmp[0] == '#') { continue; }
		if((l = strlen(tmp)) < 11) { continue; }
		if(!(payload = strchr(token, '|'))) { continue; }

		*payload++ = '\0';
		
		if(!cs_malloc(&new_provid, sizeof(struct s_provid)))
		{
			NULLFREE(token);
			fclose(fp);
			return (1);
		}
				
		new_provid->nprovid = 0;
		for(i = 0, ptr1 = strtok_r(token, ":@", &saveptr1); ptr1; ptr1 = strtok_r(NULL, ":@", &saveptr1), i++)
		{
			if(i==0)
			{
				new_provid->caid = a2i(ptr1, 3);
				continue;	
			}
			
			new_provid->nprovid++;
		}

		if(!cs_malloc(&new_provid->provid, sizeof(uint32_t) * new_provid->nprovid))
		{
			NULLFREE(new_provid);
			NULLFREE(token);
			fclose(fp);
			return (1);
		}

		ptr1 = token + strlen(token) + 1;
		for(i = 0; i < new_provid->nprovid ; i++)
		{
			new_provid->provid[i] = a2i(ptr1, 3);
			
			ptr1 = ptr1 + strlen(ptr1) + 1;
		}
		
		for(i = 0, ptr1 = strtok_r(payload, "|", &saveptr1); ptr1; ptr1 = strtok_r(NULL, "|", &saveptr1), i++)
		{
			switch(i)
			{
			case 0:
				cs_strncpy(new_provid->prov, trim(ptr1), sizeof(new_provid->prov));
				break;
			case 1:
				cs_strncpy(new_provid->sat, trim(ptr1), sizeof(new_provid->sat));
				break;
			case 2:
				cs_strncpy(new_provid->lang, trim(ptr1), sizeof(new_provid->lang));
				break;
			}
		}
		
		if(strlen(new_provid->prov) == 0)
		{
			NULLFREE(new_provid->provid);
			NULLFREE(new_provid);
			continue;
		}
		
		nr++;
				
		if(provid_ptr)
		{
			provid_ptr->next = new_provid;
		}
		else
		{ 
			new_cfg_provid = new_provid;
		}	
		provid_ptr = new_provid;
	}
	
	NULLFREE(token);
	fclose(fp);
	
	if(nr > 0)
		{ cs_log("%d provid's loaded", nr); }
	
	if(new_cfg_provid == NULL)
	{
		if(!cs_malloc(&new_cfg_provid, sizeof(struct s_provid)))
		{
			return (1);
		}		
	}
	
	cs_writelock(__func__, &config_lock);
	
	//this allows reloading of provids, so cleanup of old data is needed:
	last_provid = cfg.provid; //old data
	cfg.provid = new_cfg_provid; //assign after loading, so everything is in memory

	cs_writeunlock(__func__, &config_lock);

	struct s_client *cl;
	for(cl = first_client->next; cl ; cl = cl->next)
		{ cl->last_providptr = NULL; }

	struct s_provid *ptr, *nptr;
	
	if(last_provid)
	{
		ptr = last_provid;
		while(ptr)    //cleanup old data:
		{
			add_garbage(ptr->provid);
			nptr = ptr->next;
			add_garbage(ptr);
			ptr = nptr;
		}
	}
			
	return (0);
}