2026-02-16 09:02:48 +00:00
|
|
|
#define MODULE_LOG_PREFIX "config"
|
|
|
|
|
|
|
|
|
|
//FIXME Not checked on threadsafety yet; after checking please remove this line
|
|
|
|
|
|
|
|
|
|
#include "globals.h"
|
|
|
|
|
|
|
|
|
|
#include "oscam-conf.h"
|
|
|
|
|
#include "oscam-conf-chk.h"
|
|
|
|
|
#include "oscam-config.h"
|
|
|
|
|
#include "oscam-files.h"
|
|
|
|
|
#include "oscam-garbage.h"
|
|
|
|
|
#include "oscam-lock.h"
|
|
|
|
|
#include "oscam-string.h"
|
|
|
|
|
#include "oscam-time.h"
|
|
|
|
|
|
|
|
|
|
#define cs_srid "oscam.srvid"
|
|
|
|
|
#define cs_ratelimit "oscam.ratelimit"
|
|
|
|
|
#define cs_trid "oscam.tiers"
|
|
|
|
|
#define cs_sidt "oscam.services"
|
|
|
|
|
#define cs_whitelist "oscam.whitelist"
|
|
|
|
|
#define cs_provid "oscam.provid"
|
|
|
|
|
#define cs_fakecws "oscam.fakecws"
|
|
|
|
|
#define cs_twin "oscam.twin"
|
|
|
|
|
|
|
|
|
|
uint32_t cfg_sidtab_generation = 1;
|
|
|
|
|
uint32_t caid;
|
|
|
|
|
|
|
|
|
|
extern char cs_confdir[];
|
|
|
|
|
|
|
|
|
|
char *get_config_filename(char *dest, size_t destlen, const char *filename)
|
|
|
|
|
{
|
|
|
|
|
// cs_confdir is always terminated with /
|
|
|
|
|
snprintf(dest, destlen, "%s%s", cs_confdir, filename);
|
|
|
|
|
return dest;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int32_t write_services(void)
|
|
|
|
|
{
|
|
|
|
|
int32_t i;
|
|
|
|
|
struct s_sidtab *sidtab = cfg.sidtab;
|
|
|
|
|
char *ptr;
|
|
|
|
|
FILE *f = create_config_file(cs_sidt);
|
|
|
|
|
if(!f)
|
|
|
|
|
{ return 1; }
|
|
|
|
|
|
|
|
|
|
while(sidtab != NULL)
|
|
|
|
|
{
|
|
|
|
|
ptr = sidtab->label;
|
|
|
|
|
while(*ptr)
|
|
|
|
|
{
|
|
|
|
|
if(*ptr == ' ') { *ptr = '_'; }
|
|
|
|
|
ptr++;
|
|
|
|
|
}
|
|
|
|
|
fprintf(f, "[%s]\n", sidtab->label);
|
|
|
|
|
#ifdef CS_CACHEEX_AIO
|
|
|
|
|
fprintf_conf(f, "disablecrccws_only_for_exception", "%u", sidtab->disablecrccws_only_for_exception); // it should not have \n at the end
|
|
|
|
|
fputc((int)'\n', f);
|
|
|
|
|
fprintf_conf(f, "no_wait_time", "%u", sidtab->no_wait_time); // it should not have \n at the end
|
|
|
|
|
fputc((int)'\n', f);
|
|
|
|
|
fprintf_conf(f, "lg_only_exception", "%u", sidtab->lg_only_exception); // it should not have \n at the end
|
|
|
|
|
fputc((int)'\n', f);
|
|
|
|
|
#endif
|
|
|
|
|
fprintf_conf(f, "caid", "%s", ""); // it should not have \n at the end
|
|
|
|
|
for(i = 0; i < sidtab->num_caid; i++)
|
|
|
|
|
{
|
|
|
|
|
if(i == 0) { fprintf(f, "%04X", sidtab->caid[i]); }
|
|
|
|
|
else { fprintf(f, ",%04X", sidtab->caid[i]); }
|
|
|
|
|
}
|
|
|
|
|
fputc((int)'\n', f);
|
|
|
|
|
fprintf_conf(f, "provid", "%s", ""); // it should not have \n at the end
|
|
|
|
|
for(i = 0; i < sidtab->num_provid; i++)
|
|
|
|
|
{
|
|
|
|
|
if(i == 0) { fprintf(f, "%06X", sidtab->provid[i]); }
|
|
|
|
|
else { fprintf(f, ",%06X", sidtab->provid[i]); }
|
|
|
|
|
}
|
|
|
|
|
fputc((int)'\n', f);
|
|
|
|
|
fprintf_conf(f, "srvid", "%s", ""); // it should not have \n at the end
|
|
|
|
|
for(i = 0; i < sidtab->num_srvid; i++)
|
|
|
|
|
{
|
|
|
|
|
if(i == 0) { fprintf(f, "%04X", sidtab->srvid[i]); }
|
|
|
|
|
else { fprintf(f, ",%04X", sidtab->srvid[i]); }
|
|
|
|
|
}
|
|
|
|
|
fprintf(f, "\n\n");
|
|
|
|
|
sidtab = sidtab->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return flush_config_file(f, cs_sidt);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void free_sidtab(struct s_sidtab *ptr)
|
|
|
|
|
{
|
|
|
|
|
if(!ptr) { return; }
|
|
|
|
|
add_garbage(ptr->caid); //no need to check on NULL first, freeing NULL doesnt do anything
|
|
|
|
|
add_garbage(ptr->provid);
|
|
|
|
|
add_garbage(ptr->srvid);
|
|
|
|
|
add_garbage(ptr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void chk_entry4sidtab(char *value, struct s_sidtab *sidtab, int32_t what)
|
|
|
|
|
{
|
|
|
|
|
int32_t i, b;
|
|
|
|
|
char *ptr, *saveptr1 = NULL;
|
|
|
|
|
uint16_t *slist = (uint16_t *) 0;
|
|
|
|
|
uint32_t *llist = (uint32_t *) 0;
|
|
|
|
|
#ifdef CS_CACHEEX_AIO
|
|
|
|
|
uint8_t disablecrccws_only_for_exception = 0;
|
|
|
|
|
uint8_t no_wait_time = 0;
|
|
|
|
|
uint8_t lg_only_exception = 0;
|
|
|
|
|
#endif
|
|
|
|
|
char buf[cs_strlen(value) + 1];
|
|
|
|
|
cs_strncpy(buf, value, sizeof(buf));
|
|
|
|
|
|
|
|
|
|
#ifdef CS_CACHEEX_AIO
|
|
|
|
|
if(what == 5) // lg_only_exception
|
|
|
|
|
{
|
|
|
|
|
sidtab->lg_only_exception = a2i(buf, sizeof(lg_only_exception));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(what == 4) // no_wait_time
|
|
|
|
|
{
|
|
|
|
|
sidtab->no_wait_time = a2i(buf, sizeof(no_wait_time));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(what == 3) // disablecrccws_only_for_exception
|
|
|
|
|
{
|
|
|
|
|
sidtab->disablecrccws_only_for_exception = a2i(buf, sizeof(disablecrccws_only_for_exception));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
b = (what == 1) ? sizeof(uint32_t) : sizeof(uint16_t);
|
|
|
|
|
|
|
|
|
|
for(i = 0, ptr = strtok_r(value, ",", &saveptr1); ptr; ptr = strtok_r(NULL, ",", &saveptr1))
|
|
|
|
|
{
|
|
|
|
|
caid = a2i(ptr, b);
|
|
|
|
|
if(!errno) { i++; }
|
|
|
|
|
}
|
|
|
|
|
//if (!i) return(0);
|
|
|
|
|
if(b == sizeof(uint16_t))
|
|
|
|
|
{
|
|
|
|
|
if(!cs_malloc(&slist, i * sizeof(uint16_t))) { return; }
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if(!cs_malloc(&llist, i * sizeof(uint32_t))) { return; }
|
|
|
|
|
}
|
|
|
|
|
cs_strncpy(value, buf, sizeof(buf));
|
|
|
|
|
for(i = 0, ptr = strtok_r(value, ",", &saveptr1); ptr; ptr = strtok_r(NULL, ",", &saveptr1))
|
|
|
|
|
{
|
|
|
|
|
caid = a2i(ptr, b);
|
|
|
|
|
if(errno) { continue; }
|
|
|
|
|
if(b == sizeof(uint16_t))
|
|
|
|
|
{ slist[i++] = (uint16_t) caid; }
|
|
|
|
|
else
|
|
|
|
|
{ llist[i++] = caid; }
|
|
|
|
|
}
|
|
|
|
|
switch(what)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
add_garbage(sidtab->caid);
|
|
|
|
|
sidtab->caid = slist;
|
|
|
|
|
sidtab->num_caid = i;
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
add_garbage(sidtab->provid);
|
|
|
|
|
sidtab->provid = llist;
|
|
|
|
|
sidtab->num_provid = i;
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
add_garbage(sidtab->srvid);
|
|
|
|
|
sidtab->srvid = slist;
|
|
|
|
|
sidtab->num_srvid = i;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void chk_sidtab(char *token, char *value, struct s_sidtab *sidtab)
|
|
|
|
|
{
|
|
|
|
|
if(!strcmp(token, "caid"))
|
|
|
|
|
{
|
|
|
|
|
chk_entry4sidtab(value, sidtab, 0);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if(!strcmp(token, "provid"))
|
|
|
|
|
{
|
|
|
|
|
chk_entry4sidtab(value, sidtab, 1);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if(!strcmp(token, "ident"))
|
|
|
|
|
{
|
|
|
|
|
chk_entry4sidtab(value, sidtab, 1);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if(!strcmp(token, "srvid"))
|
|
|
|
|
{
|
|
|
|
|
chk_entry4sidtab(value, sidtab, 2);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
#ifdef CS_CACHEEX_AIO
|
|
|
|
|
if(!strcmp(token, "disablecrccws_only_for_exception"))
|
|
|
|
|
{
|
|
|
|
|
chk_entry4sidtab(value, sidtab, 3);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if(!strcmp(token, "no_wait_time"))
|
|
|
|
|
{
|
|
|
|
|
chk_entry4sidtab(value, sidtab, 4);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if(!strcmp(token, "lg_only_exception"))
|
|
|
|
|
{
|
|
|
|
|
chk_entry4sidtab(value, sidtab, 5);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
if(token[0] != '#')
|
|
|
|
|
{ fprintf(stderr, "Warning: keyword '%s' in sidtab section not recognized\n", token); }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void init_free_sidtab(void)
|
|
|
|
|
{
|
|
|
|
|
struct s_sidtab *nxt, *ptr = cfg.sidtab;
|
|
|
|
|
while(ptr)
|
|
|
|
|
{
|
|
|
|
|
nxt = ptr->next;
|
|
|
|
|
free_sidtab(ptr);
|
|
|
|
|
ptr = nxt;
|
|
|
|
|
}
|
|
|
|
|
cfg.sidtab = NULL;
|
|
|
|
|
++cfg_sidtab_generation;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//#define DEBUG_SIDTAB 1
|
|
|
|
|
#ifdef DEBUG_SIDTAB
|
|
|
|
|
static void show_sidtab(struct s_sidtab *sidtab)
|
|
|
|
|
{
|
|
|
|
|
for(; sidtab; sidtab = sidtab->next)
|
|
|
|
|
{
|
|
|
|
|
int32_t i;
|
|
|
|
|
char buf[1024];
|
|
|
|
|
char *saveptr = buf;
|
|
|
|
|
cs_log("label=%s", sidtab->label);
|
|
|
|
|
#ifdef CS_CACHEEX_AIO
|
|
|
|
|
cs_log("disablecrccws_only_for_exception=%u", sidtab->disablecrccws_only_for_exception);
|
|
|
|
|
cs_log("no_wait_time=%u", sidtab->no_wait_time);
|
|
|
|
|
cs_log("lg_only_exception=%u", sidtab->lg_only_exception);
|
|
|
|
|
#endif
|
|
|
|
|
snprintf(buf, sizeof(buf), "caid(%d)=", sidtab->num_caid);
|
|
|
|
|
for(i = 0; i < sidtab->num_caid; i++)
|
|
|
|
|
{ snprintf(buf + cs_strlen(buf), 1024 - (buf - saveptr), "%04X ", sidtab->caid[i]); }
|
|
|
|
|
cs_log("%s", buf);
|
|
|
|
|
snprintf(buf, sizeof(buf), "provider(%d)=", sidtab->num_provid);
|
|
|
|
|
for(i = 0; i < sidtab->num_provid; i++)
|
|
|
|
|
{ snprintf(buf + cs_strlen(buf), 1024 - (buf - saveptr), "%08X ", sidtab->provid[i]); }
|
|
|
|
|
cs_log("%s", buf);
|
|
|
|
|
snprintf(buf, sizeof(buf), "services(%d)=", sidtab->num_srvid);
|
|
|
|
|
for(i = 0; i < sidtab->num_srvid; i++)
|
|
|
|
|
{ snprintf(buf + cs_strlen(buf), 1024 - (buf - saveptr), "%04X ", sidtab->srvid[i]); }
|
|
|
|
|
cs_log("%s", buf);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
static void show_sidtab(struct s_sidtab *UNUSED(sidtab)) { }
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
int32_t init_sidtab(void)
|
|
|
|
|
{
|
|
|
|
|
FILE *fp = open_config_file(cs_sidt);
|
|
|
|
|
if(!fp)
|
|
|
|
|
{ return 1; }
|
|
|
|
|
|
|
|
|
|
int32_t nr, nro, nrr;
|
|
|
|
|
char *value, *token;
|
|
|
|
|
if(!cs_malloc(&token, MAXLINESIZE))
|
|
|
|
|
{ return 1; }
|
|
|
|
|
struct s_sidtab *ptr;
|
|
|
|
|
struct s_sidtab *sidtab = (struct s_sidtab *)0;
|
|
|
|
|
|
|
|
|
|
for(nro = 0, ptr = cfg.sidtab; ptr; nro++)
|
|
|
|
|
{
|
|
|
|
|
struct s_sidtab *ptr_next;
|
|
|
|
|
ptr_next = ptr->next;
|
|
|
|
|
free_sidtab(ptr);
|
|
|
|
|
ptr = ptr_next;
|
|
|
|
|
}
|
|
|
|
|
nr = 0;
|
|
|
|
|
nrr = 0;
|
|
|
|
|
while(fgets(token, MAXLINESIZE, fp))
|
|
|
|
|
{
|
|
|
|
|
int32_t l;
|
|
|
|
|
if((l = cs_strlen(trim(token))) < 3) { continue; }
|
|
|
|
|
if((token[0] == '[') && (token[l - 1] == ']'))
|
|
|
|
|
{
|
|
|
|
|
token[l - 1] = 0;
|
|
|
|
|
if(nr > MAX_SIDBITS)
|
|
|
|
|
{
|
|
|
|
|
fprintf(stderr, "Warning: Service No.%d - '%s' ignored. Max allowed Services %d\n", nr, strtolower(token + 1), MAX_SIDBITS);
|
|
|
|
|
nr++;
|
|
|
|
|
nrr++;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if(!cs_malloc(&ptr, sizeof(struct s_sidtab)))
|
|
|
|
|
{
|
|
|
|
|
NULLFREE(token);
|
|
|
|
|
return (1);
|
|
|
|
|
}
|
|
|
|
|
if(sidtab)
|
|
|
|
|
{ sidtab->next = ptr; }
|
|
|
|
|
else
|
|
|
|
|
{ cfg.sidtab = ptr; }
|
|
|
|
|
sidtab = ptr;
|
|
|
|
|
nr++;
|
|
|
|
|
cs_strncpy(sidtab->label, strtolower(token + 1), sizeof(sidtab->label));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(!sidtab) { continue; }
|
|
|
|
|
if(!(value = strchr(token, '='))) { continue; }
|
|
|
|
|
*value++ = '\0';
|
|
|
|
|
chk_sidtab(trim(strtolower(token)), trim(strtolower(value)), sidtab);
|
|
|
|
|
}
|
|
|
|
|
NULLFREE(token);
|
|
|
|
|
fclose(fp);
|
|
|
|
|
|
|
|
|
|
show_sidtab(cfg.sidtab);
|
|
|
|
|
++cfg_sidtab_generation;
|
|
|
|
|
cs_log("services reloaded: %d services freed, %d services loaded, rejected %d", nro, nr, nrr);
|
|
|
|
|
return (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;
|
|
|
|
|
struct s_provid *new_provid = NULL;
|
|
|
|
|
char *tmp, *ptr1;
|
|
|
|
|
|
|
|
|
|
tmp = trim(token);
|
|
|
|
|
|
|
|
|
|
if(tmp[0] == '#') { continue; }
|
|
|
|
|
if(cs_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 + cs_strlen(token) + 1;
|
|
|
|
|
for(i = 0; i < new_provid->nprovid ; i++)
|
|
|
|
|
{
|
|
|
|
|
new_provid->provid[i] = a2i(ptr1, 3);
|
|
|
|
|
|
|
|
|
|
ptr1 = ptr1 + cs_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(cs_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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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 len = 0, len2, srvidtmp;
|
|
|
|
|
uint32_t k;
|
|
|
|
|
uint32_t pos;
|
|
|
|
|
char *srvidasc, *prov;
|
|
|
|
|
tmp = trim(token);
|
|
|
|
|
|
|
|
|
|
if(tmp[0] == '#') { continue; }
|
|
|
|
|
if(cs_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] == '|' && (cs_strlen(payload) + 2 < max_payload_length))
|
|
|
|
|
{
|
|
|
|
|
memmove(payload+1, payload, cs_strlen(payload)+1);
|
|
|
|
|
payload[0] = ' ';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for(k = 1; ((k < max_payload_length) && (payload[k] != '\0')); k++)
|
|
|
|
|
{
|
|
|
|
|
if(payload[k - 1] == '|' && payload[k] == '|')
|
|
|
|
|
{
|
|
|
|
|
if(cs_strlen(payload + k) + 2 < max_payload_length-k)
|
|
|
|
|
{
|
|
|
|
|
memmove(payload + k + 1, payload + k, cs_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 = cs_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 += cs_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
|
|
|
|
|
if (*ptrs[i])
|
|
|
|
|
{
|
|
|
|
|
tmp = *ptrs[i];
|
|
|
|
|
len2 = cs_strlen(tmp);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
cs_log("FIXME! len2!");
|
|
|
|
|
len2 = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pos = 0;
|
|
|
|
|
for(j = 0; j < len2; ++j) { pos += (uint8_t)tmp[j]; }
|
|
|
|
|
if (pos > 0)
|
|
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
if (tmp[0])
|
|
|
|
|
{
|
|
|
|
|
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 + cs_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 + cs_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;
|
|
|
|
|
}
|
|
|
|
|
for(i = 0; i < 1024; ++i)
|
|
|
|
|
{
|
|
|
|
|
if(allocated[i] > 0) { NULLFREE(stringcache[i]); }
|
|
|
|
|
}
|
|
|
|
|
NULLFREE(token);
|
|
|
|
|
|
|
|
|
|
cs_ftime(&te);
|
|
|
|
|
int64_t load_time = comp_timeb(&te, &ts);
|
|
|
|
|
|
|
|
|
|
fclose(fp);
|
|
|
|
|
if(nr > 0)
|
|
|
|
|
{
|
|
|
|
|
cs_log("%d service-id's loaded in %"PRId64" ms", nr, load_time);
|
|
|
|
|
if(nr > 2000)
|
|
|
|
|
{
|
|
|
|
|
cs_log("WARNING: You risk high CPU load and high ECM times with more than 2000 service-id's!");
|
|
|
|
|
cs_log("HINT: --> use optimized lists from %s/Srvid", WIKI_URL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cs_writelock(__func__, &config_lock);
|
|
|
|
|
// this allows reloading of srvids, so cleanup of old data is needed:
|
|
|
|
|
memcpy(last_srvid, cfg.srvid, sizeof(last_srvid)); //old data
|
|
|
|
|
memcpy(cfg.srvid, new_cfg_srvid, sizeof(last_srvid)); //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_srvidptr = NULL; }
|
|
|
|
|
|
|
|
|
|
struct s_srvid *ptr, *nptr;
|
|
|
|
|
|
|
|
|
|
for(i = 0; i < 16; i++)
|
|
|
|
|
{
|
|
|
|
|
ptr = last_srvid[i];
|
|
|
|
|
while(ptr) // cleanup old data:
|
|
|
|
|
{
|
|
|
|
|
for(j = 0; j < ptr->ncaid; j++)
|
|
|
|
|
{ add_garbage(ptr->caid[j].provid); }
|
|
|
|
|
add_garbage(ptr->caid);
|
|
|
|
|
add_garbage(ptr->data);
|
|
|
|
|
nptr = ptr->next;
|
|
|
|
|
add_garbage(ptr);
|
|
|
|
|
ptr = nptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int32_t init_fakecws(void)
|
|
|
|
|
{
|
|
|
|
|
int32_t nr = 0, i, j, idx;
|
|
|
|
|
uint32_t alloccount[0x100], count[0x100], tmp, max_compares = 0, average_compares = 0;
|
|
|
|
|
char *token, cw_string[64];
|
2026-02-17 23:10:20 +00:00
|
|
|
uint8_t cw[16], wrong_checksum, __attribute__((unused)) c, have_fakecw = 0;
|
2026-02-16 09:02:48 +00:00
|
|
|
FILE *fp;
|
|
|
|
|
|
|
|
|
|
memset(alloccount, 0, sizeof(count));
|
|
|
|
|
memset(count, 0, sizeof(alloccount));
|
|
|
|
|
|
|
|
|
|
cs_writelock(__func__, &config_lock);
|
|
|
|
|
for(i = 0; i < 0x100; i++)
|
|
|
|
|
{
|
|
|
|
|
cfg.fakecws[i].count = 0;
|
|
|
|
|
NULLFREE(cfg.fakecws[i].data);
|
|
|
|
|
}
|
|
|
|
|
cs_writeunlock(__func__, &config_lock);
|
|
|
|
|
|
|
|
|
|
fp = open_config_file(cs_fakecws);
|
|
|
|
|
if(!fp)
|
|
|
|
|
{ return 0; }
|
|
|
|
|
|
|
|
|
|
if(!cs_malloc(&token, MAXLINESIZE))
|
|
|
|
|
{ return 0; }
|
|
|
|
|
|
|
|
|
|
while(fgets(token, MAXLINESIZE, fp))
|
|
|
|
|
{
|
|
|
|
|
if(sscanf(token, " %62s ", cw_string) == 1)
|
|
|
|
|
{
|
|
|
|
|
if(cs_strlen(cw_string) == 32)
|
|
|
|
|
{
|
|
|
|
|
if(cs_atob(cw, cw_string, 16) == 16)
|
|
|
|
|
{
|
|
|
|
|
wrong_checksum = 0;
|
|
|
|
|
|
|
|
|
|
if(wrong_checksum)
|
|
|
|
|
{
|
|
|
|
|
cs_log("skipping fake cw %s because of wrong checksum!", cw_string);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
idx = ((cw[0] & 0xF) << 4) | (cw[8] & 0xF);
|
|
|
|
|
alloccount[idx]++;
|
|
|
|
|
have_fakecw = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
cs_log("skipping fake cw %s because it contains invalid characters!", cw_string);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
cs_log("skipping fake cw %s because of wrong length (%u != 32)!", cw_string, (uint32_t)cs_strlen(cw_string));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(!have_fakecw)
|
|
|
|
|
{
|
|
|
|
|
NULLFREE(token);
|
|
|
|
|
fclose(fp);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for(i = 0; i < 0x100; i++)
|
|
|
|
|
{
|
|
|
|
|
if(alloccount[i] && !cs_malloc(&cfg.fakecws[i].data, sizeof(struct s_cw)*alloccount[i]))
|
|
|
|
|
{
|
|
|
|
|
alloccount[i] = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fseek(fp, 0, SEEK_SET);
|
|
|
|
|
|
|
|
|
|
while(fgets(token, MAXLINESIZE, fp))
|
|
|
|
|
{
|
|
|
|
|
if(sscanf(token, " %62s ", cw_string) == 1)
|
|
|
|
|
{
|
|
|
|
|
if(cs_strlen(cw_string) == 32)
|
|
|
|
|
{
|
|
|
|
|
if(cs_atob(cw, cw_string, 16) == 16)
|
|
|
|
|
{
|
|
|
|
|
wrong_checksum = 0;
|
|
|
|
|
|
|
|
|
|
if(!wrong_checksum)
|
|
|
|
|
{
|
|
|
|
|
idx = ((cw[0] & 0xF) << 4) | (cw[8] & 0xF);
|
|
|
|
|
|
|
|
|
|
if(count[idx] < alloccount[idx])
|
|
|
|
|
{
|
|
|
|
|
memcpy(cfg.fakecws[idx].data[count[idx]].cw, cw, 16);
|
|
|
|
|
count[idx]++;
|
|
|
|
|
nr++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NULLFREE(token);
|
|
|
|
|
fclose(fp);
|
|
|
|
|
|
|
|
|
|
if(nr > 0)
|
|
|
|
|
{ cs_log("%d fakecws's loaded", nr); }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cs_writelock(__func__, &config_lock);
|
|
|
|
|
for(i = 0; i < 0x100; i++)
|
|
|
|
|
{
|
|
|
|
|
cfg.fakecws[i].count = count[i];
|
|
|
|
|
}
|
|
|
|
|
cs_writeunlock(__func__, &config_lock);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for(i = 0; i < 0x100; i++)
|
|
|
|
|
{
|
|
|
|
|
if(count[i] > max_compares)
|
|
|
|
|
{ max_compares = count[i]; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for(i = 0; i < (0x100 - 1); i++)
|
|
|
|
|
{
|
|
|
|
|
for(j = i + 1; j < 0x100; j++)
|
|
|
|
|
{
|
|
|
|
|
if(count[j] < count[i])
|
|
|
|
|
{
|
|
|
|
|
tmp = count[i];
|
|
|
|
|
count[i] = count[j];
|
|
|
|
|
count[j] = tmp;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
average_compares = ((count[0x100 / 2] + count[0x100 / 2 - 1]) / 2);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cs_log("max %d fakecw compares required, on average: %d compares", max_compares, average_compares);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct s_rlimit *ratelimit_read_int(void)
|
|
|
|
|
{
|
|
|
|
|
FILE *fp = open_config_file(cs_ratelimit);
|
|
|
|
|
if(!fp)
|
|
|
|
|
{ return NULL; }
|
|
|
|
|
char token[1024], str1[1024];
|
|
|
|
|
int32_t i, ret, count = 0;
|
|
|
|
|
struct s_rlimit *new_rlimit = NULL, *entry, *last = NULL;
|
|
|
|
|
|
|
|
|
|
while(fgets(token, sizeof(token), fp))
|
|
|
|
|
{
|
|
|
|
|
if(cs_strlen(token) <= 1) { continue; }
|
|
|
|
|
if(token[0] == '#' || token[0] == '/') { continue; }
|
|
|
|
|
if(cs_strlen(token) > 1024) { continue; }
|
|
|
|
|
|
|
|
|
|
for(i = 0; i < (int)cs_strlen(token); i++)
|
|
|
|
|
{
|
|
|
|
|
if((token[i] == ':' || token[i] == ' ') && token[i + 1] == ':')
|
|
|
|
|
{
|
|
|
|
|
memmove(token + i + 2, token + i + 1, cs_strlen(token) - i + 1);
|
|
|
|
|
token[i + 1] = '0';
|
|
|
|
|
}
|
|
|
|
|
if(token[i] == '#' || token[i] == '/')
|
|
|
|
|
{
|
|
|
|
|
token[i] = '\0';
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
caid = 0;
|
|
|
|
|
uint32_t provid = 0, srvid = 0, chid = 0, ratelimitecm = 0, ratelimittime = 0, srvidholdtime = 0;
|
|
|
|
|
memset(str1, 0, sizeof(str1));
|
|
|
|
|
|
|
|
|
|
ret = sscanf(token, "%4x:%6x:%4x:%4x:%d:%d:%d:%1023s", &caid, &provid, &srvid, &chid, &ratelimitecm, &ratelimittime, &srvidholdtime, str1);
|
|
|
|
|
if(ret < 1) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!cs_strncat(str1, ",", sizeof(str1))) {
|
|
|
|
|
return new_rlimit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(!cs_malloc(&entry, sizeof(struct s_rlimit)))
|
|
|
|
|
{
|
|
|
|
|
fclose(fp);
|
|
|
|
|
return new_rlimit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
count++;
|
|
|
|
|
if (ratelimittime < 60) ratelimittime *= 1000;
|
|
|
|
|
if (srvidholdtime < 60) srvidholdtime *= 1000;
|
|
|
|
|
entry->rl.caid = caid;
|
|
|
|
|
entry->rl.provid = provid;
|
|
|
|
|
entry->rl.srvid = srvid;
|
|
|
|
|
entry->rl.chid = chid;
|
|
|
|
|
entry->rl.ratelimitecm = ratelimitecm;
|
|
|
|
|
entry->rl.ratelimittime = ratelimittime;
|
|
|
|
|
entry->rl.srvidholdtime = srvidholdtime;
|
|
|
|
|
|
|
|
|
|
cs_log_dbg(D_TRACE, "ratelimit: %04X@%06X:%04X:%04X:%d:%d:%d", entry->rl.caid, entry->rl.provid, entry->rl.srvid, entry->rl.chid,
|
|
|
|
|
entry->rl.ratelimitecm, entry->rl.ratelimittime, entry->rl.srvidholdtime);
|
|
|
|
|
|
|
|
|
|
if(!new_rlimit)
|
|
|
|
|
{
|
|
|
|
|
new_rlimit = entry;
|
|
|
|
|
last = new_rlimit;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
last->next = entry;
|
|
|
|
|
last = entry;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(count)
|
|
|
|
|
{ cs_log("%d entries read from %s", count, cs_ratelimit); }
|
|
|
|
|
|
|
|
|
|
fclose(fp);
|
|
|
|
|
|
|
|
|
|
return new_rlimit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ratelimit_read(void)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
struct s_rlimit *entry, *old_list;
|
|
|
|
|
|
|
|
|
|
old_list = cfg.ratelimit_list;
|
|
|
|
|
cfg.ratelimit_list = ratelimit_read_int();
|
|
|
|
|
|
|
|
|
|
while(old_list)
|
|
|
|
|
{
|
|
|
|
|
entry = old_list->next;
|
|
|
|
|
NULLFREE(old_list);
|
|
|
|
|
old_list = entry;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct ecmrl get_ratelimit(ECM_REQUEST *er)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
struct ecmrl tmp;
|
|
|
|
|
memset(&tmp, 0, sizeof(tmp));
|
|
|
|
|
if(!cfg.ratelimit_list) { return tmp; }
|
|
|
|
|
struct s_rlimit *entry = cfg.ratelimit_list;
|
|
|
|
|
while(entry)
|
|
|
|
|
{
|
|
|
|
|
if(entry->rl.caid == er->caid && entry->rl.provid == er->prid && entry->rl.srvid == er->srvid && (!entry->rl.chid || entry->rl.chid == er->chid))
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
entry = entry->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(entry) { tmp = entry->rl; }
|
|
|
|
|
|
|
|
|
|
return (tmp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int32_t init_tierid(void)
|
|
|
|
|
{
|
|
|
|
|
FILE *fp = open_config_file(cs_trid);
|
|
|
|
|
if(!fp)
|
|
|
|
|
{ return 0; }
|
|
|
|
|
|
|
|
|
|
int32_t nr;
|
|
|
|
|
char *payload, *saveptr1 = NULL, *token;
|
|
|
|
|
if(!cs_malloc(&token, MAXLINESIZE))
|
|
|
|
|
{ return 0; }
|
|
|
|
|
static struct s_tierid *tierid = NULL, *new_cfg_tierid = NULL;
|
|
|
|
|
|
|
|
|
|
nr = 0;
|
|
|
|
|
while(fgets(token, MAXLINESIZE, fp))
|
|
|
|
|
{
|
|
|
|
|
void *ptr;
|
|
|
|
|
char *tmp, *tieridasc;
|
|
|
|
|
tmp = trim(token);
|
|
|
|
|
|
|
|
|
|
if(tmp[0] == '#') { continue; }
|
|
|
|
|
if(cs_strlen(tmp) < 6) { continue; }
|
|
|
|
|
if(!(payload = strchr(token, '|'))) { continue; }
|
|
|
|
|
if(!(tieridasc = strchr(token, ':'))) { continue; }
|
|
|
|
|
*payload++ = '\0';
|
|
|
|
|
|
|
|
|
|
if(!cs_malloc(&ptr, sizeof(struct s_tierid)))
|
|
|
|
|
{
|
|
|
|
|
NULLFREE(token);
|
|
|
|
|
fclose(fp);
|
|
|
|
|
return (1);
|
|
|
|
|
}
|
|
|
|
|
if(tierid)
|
|
|
|
|
{ tierid->next = ptr; }
|
|
|
|
|
else
|
|
|
|
|
{ new_cfg_tierid = ptr; }
|
|
|
|
|
|
|
|
|
|
tierid = ptr;
|
|
|
|
|
|
|
|
|
|
int32_t i;
|
|
|
|
|
char *ptr1 = strtok_r(payload, "|", &saveptr1);
|
|
|
|
|
if(ptr1)
|
|
|
|
|
{ cs_strncpy(tierid->name, trim(ptr1), sizeof(tierid->name)); }
|
|
|
|
|
|
|
|
|
|
*tieridasc++ = '\0';
|
|
|
|
|
tierid->tierid = dyn_word_atob(tieridasc);
|
|
|
|
|
//printf("tierid %s - %d\n",tieridasc,tierid->tierid );
|
|
|
|
|
|
|
|
|
|
tierid->ncaid = 0;
|
|
|
|
|
for(i = 0, ptr1 = strtok_r(token, ",", &saveptr1); (ptr1) && (i < 10) ; ptr1 = strtok_r(NULL, ",", &saveptr1), i++)
|
|
|
|
|
{
|
|
|
|
|
tierid->caid[i] = dyn_word_atob(ptr1);
|
|
|
|
|
tierid->ncaid = i + 1;
|
|
|
|
|
//cs_log("ld caid: %04X tierid: %04X name: %s",tierid->caid[i],tierid->tierid,tierid->name);
|
|
|
|
|
}
|
|
|
|
|
nr++;
|
|
|
|
|
}
|
|
|
|
|
NULLFREE(token);
|
|
|
|
|
fclose(fp);
|
|
|
|
|
if(nr > 0)
|
|
|
|
|
{ cs_log("%d tier-id's loaded", nr); }
|
|
|
|
|
cs_writelock(__func__, &config_lock);
|
|
|
|
|
// reload function:
|
|
|
|
|
tierid = cfg.tierid;
|
|
|
|
|
cfg.tierid = new_cfg_tierid;
|
|
|
|
|
struct s_tierid *ptr;
|
|
|
|
|
while(tierid)
|
|
|
|
|
{
|
|
|
|
|
ptr = tierid->next;
|
|
|
|
|
NULLFREE(tierid);
|
|
|
|
|
tierid = ptr;
|
|
|
|
|
}
|
|
|
|
|
cs_writeunlock(__func__, &config_lock);
|
|
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int32_t match_whitelist(ECM_REQUEST *er, struct s_global_whitelist *entry)
|
|
|
|
|
{
|
|
|
|
|
return ((!entry->caid || entry->caid == er->caid)
|
|
|
|
|
&& (!entry->provid || entry->provid == er->prid)
|
|
|
|
|
&& (!entry->srvid || entry->srvid == er->srvid)
|
|
|
|
|
&& (!entry->chid || entry->chid == er->chid)
|
|
|
|
|
&& (!entry->pid || entry->pid == er->pid)
|
|
|
|
|
&& (!entry->ecmlen || entry->ecmlen == er->ecmlen));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int32_t chk_global_whitelist(ECM_REQUEST *er, uint32_t *line)
|
|
|
|
|
{
|
|
|
|
|
*line = -1;
|
|
|
|
|
if(!cfg.global_whitelist)
|
|
|
|
|
{ return 1; }
|
|
|
|
|
|
|
|
|
|
struct s_global_whitelist *entry;
|
|
|
|
|
|
|
|
|
|
// check mapping:
|
|
|
|
|
if(cfg.global_whitelist_use_m)
|
|
|
|
|
{
|
|
|
|
|
entry = cfg.global_whitelist;
|
|
|
|
|
while(entry)
|
|
|
|
|
{
|
|
|
|
|
if(entry->type == 'm')
|
|
|
|
|
{
|
|
|
|
|
if(match_whitelist(er, entry))
|
|
|
|
|
{
|
|
|
|
|
cs_log_dbg(D_TRACE, "whitelist: mapped %04X@%06X to %04X@%06X", er->caid, er->prid, entry->mapcaid, entry->mapprovid);
|
|
|
|
|
er->caid = entry->mapcaid;
|
|
|
|
|
er->prid = entry->mapprovid;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
entry = entry->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(cfg.global_whitelist_use_l) // Check caid/prov/srvid etc matching, except ecm-len:
|
|
|
|
|
{
|
|
|
|
|
entry = cfg.global_whitelist;
|
|
|
|
|
int8_t caidprov_matches = 0;
|
|
|
|
|
while(entry)
|
|
|
|
|
{
|
|
|
|
|
if(entry->type == 'l')
|
|
|
|
|
{
|
|
|
|
|
if(match_whitelist(er, entry))
|
|
|
|
|
{
|
|
|
|
|
*line = entry->line;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
if((!entry->caid || entry->caid == er->caid)
|
|
|
|
|
&& (!entry->provid || entry->provid == er->prid)
|
|
|
|
|
&& (!entry->srvid || entry->srvid == er->srvid)
|
|
|
|
|
&& (!entry->chid || entry->chid == er->chid)
|
|
|
|
|
&& (!entry->pid || entry->pid == er->pid))
|
|
|
|
|
{
|
|
|
|
|
caidprov_matches = 1;
|
|
|
|
|
*line = entry->line;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
entry = entry->next;
|
|
|
|
|
}
|
|
|
|
|
if(caidprov_matches) // ...but not ecm-len!
|
|
|
|
|
{ return 0; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
entry = cfg.global_whitelist;
|
|
|
|
|
while(entry)
|
|
|
|
|
{
|
|
|
|
|
if(match_whitelist(er, entry))
|
|
|
|
|
{
|
|
|
|
|
*line = entry->line;
|
|
|
|
|
if(entry->type == 'w')
|
|
|
|
|
{ return 1; }
|
|
|
|
|
else if(entry->type == 'i')
|
|
|
|
|
{ return 0; }
|
|
|
|
|
}
|
|
|
|
|
entry = entry->next;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Format:
|
|
|
|
|
//Whitelist-Entry:
|
|
|
|
|
//w:caid:prov:srvid:pid:chid:ecmlen
|
|
|
|
|
//Ignore-Entry:
|
|
|
|
|
//i:caid:prov:srvid:pid:chid:ecmlen
|
|
|
|
|
//ECM len check - Entry:
|
|
|
|
|
//l:caid:prov:srvid:pid:chid:ecmlen
|
|
|
|
|
|
|
|
|
|
//Mapping:
|
|
|
|
|
//m:caid:prov:srvid:pid:chid:ecmlen caidto:provto
|
|
|
|
|
|
|
|
|
|
static struct s_global_whitelist *global_whitelist_read_int(void)
|
|
|
|
|
{
|
|
|
|
|
FILE *fp = open_config_file(cs_whitelist);
|
|
|
|
|
if(!fp)
|
|
|
|
|
{ return NULL; }
|
|
|
|
|
|
|
|
|
|
char token[1024], str1[1024];
|
|
|
|
|
uint8_t type;
|
|
|
|
|
int32_t i, ret, count = 0;
|
|
|
|
|
struct s_global_whitelist *new_whitelist = NULL, *entry, *last = NULL;
|
|
|
|
|
uint32_t line = 0;
|
|
|
|
|
|
|
|
|
|
cfg.global_whitelist_use_l = 0;
|
|
|
|
|
cfg.global_whitelist_use_m = 0;
|
|
|
|
|
|
|
|
|
|
while(fgets(token, sizeof(token), fp))
|
|
|
|
|
{
|
|
|
|
|
line++;
|
|
|
|
|
if(cs_strlen(token) <= 1) { continue; }
|
|
|
|
|
if(token[0] == '#' || token[0] == '/') { continue; }
|
|
|
|
|
if(cs_strlen(token) > 1024) { continue; }
|
|
|
|
|
|
|
|
|
|
for(i = 0; i < (int)cs_strlen(token); i++)
|
|
|
|
|
{
|
|
|
|
|
if((token[i] == ':' || token[i] == ' ') && token[i + 1] == ':')
|
|
|
|
|
{
|
|
|
|
|
memmove(token + i + 2, token + i + 1, cs_strlen(token) - i + 1);
|
|
|
|
|
token[i + 1] = '0';
|
|
|
|
|
}
|
|
|
|
|
if(token[i] == '#' || token[i] == '/')
|
|
|
|
|
{
|
|
|
|
|
token[i] = '\0';
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type = 'w';
|
|
|
|
|
caid = 0;
|
|
|
|
|
uint32_t provid = 0, srvid = 0, pid = 0, chid = 0, ecmlen = 0, mapcaid = 0, mapprovid = 0;
|
|
|
|
|
memset(str1, 0, sizeof(str1));
|
|
|
|
|
|
|
|
|
|
ret = sscanf(token, "%c:%4x:%6x:%4x:%4x:%4x:%1023s", &type, &caid, &provid, &srvid, &pid, &chid, str1);
|
|
|
|
|
|
|
|
|
|
type = tolower(type);
|
|
|
|
|
|
|
|
|
|
//w=whitelist
|
|
|
|
|
//i=ignore
|
|
|
|
|
//l=len-check
|
|
|
|
|
//m=map caid/prov
|
|
|
|
|
if(ret < 1 || (type != 'w' && type != 'i' && type != 'l' && type != 'm'))
|
|
|
|
|
{ continue; }
|
|
|
|
|
|
|
|
|
|
if(type == 'm')
|
|
|
|
|
{
|
|
|
|
|
char *p = strstr(token + 4, " ");
|
|
|
|
|
if(!p || sscanf(p + 1, "%4x:%6x", &mapcaid, &mapprovid) < 2)
|
|
|
|
|
{
|
|
|
|
|
cs_log_dbg(D_TRACE, "whitelist: wrong mapping: %s", token);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
str1[0] = 0;
|
|
|
|
|
cfg.global_whitelist_use_m = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!cs_strncat(str1, ",", sizeof(str1))) {
|
|
|
|
|
return new_whitelist;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char *p = str1, *p2 = str1;
|
|
|
|
|
|
|
|
|
|
while(*p)
|
|
|
|
|
{
|
|
|
|
|
if(*p == ',')
|
|
|
|
|
{
|
|
|
|
|
*p = 0;
|
|
|
|
|
ecmlen = 0;
|
|
|
|
|
sscanf(p2, "%4x", &ecmlen);
|
|
|
|
|
|
|
|
|
|
if(!cs_malloc(&entry, sizeof(struct s_global_whitelist)))
|
|
|
|
|
{
|
|
|
|
|
fclose(fp);
|
|
|
|
|
return new_whitelist;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
count++;
|
|
|
|
|
entry->line = line;
|
|
|
|
|
entry->type = type;
|
|
|
|
|
entry->caid = caid;
|
|
|
|
|
entry->provid = provid;
|
|
|
|
|
entry->srvid = srvid;
|
|
|
|
|
entry->pid = pid;
|
|
|
|
|
entry->chid = chid;
|
|
|
|
|
entry->ecmlen = ecmlen;
|
|
|
|
|
entry->mapcaid = mapcaid;
|
|
|
|
|
entry->mapprovid = mapprovid;
|
|
|
|
|
if(entry->type == 'l')
|
|
|
|
|
{ cfg.global_whitelist_use_l = 1; }
|
|
|
|
|
|
|
|
|
|
if(type == 'm')
|
|
|
|
|
cs_log_dbg(D_TRACE, "whitelist: %c: %04X@%06X:%04X:%04X:%04X:%02X map to %04X@%06X",
|
|
|
|
|
entry->type, entry->caid, entry->provid, entry->srvid, entry->pid, entry->chid, entry->ecmlen, entry->mapcaid, entry->mapprovid);
|
|
|
|
|
else
|
|
|
|
|
cs_log_dbg(D_TRACE, "whitelist: %c: %04X@%06X:%04X:%04X:%04X:%02X",
|
|
|
|
|
entry->type, entry->caid, entry->provid, entry->srvid, entry->pid, entry->chid, entry->ecmlen);
|
|
|
|
|
|
|
|
|
|
if(!new_whitelist)
|
|
|
|
|
{
|
|
|
|
|
new_whitelist = entry;
|
|
|
|
|
last = new_whitelist;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
last->next = entry;
|
|
|
|
|
last = entry;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p2 = p + 1;
|
|
|
|
|
}
|
|
|
|
|
p++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(count)
|
|
|
|
|
{ cs_log("%d entries read from %s", count, cs_whitelist); }
|
|
|
|
|
|
|
|
|
|
fclose(fp);
|
|
|
|
|
|
|
|
|
|
return new_whitelist;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void global_whitelist_read(void)
|
|
|
|
|
{
|
|
|
|
|
struct s_global_whitelist *entry, *old_list;
|
|
|
|
|
|
|
|
|
|
old_list = cfg.global_whitelist;
|
|
|
|
|
cfg.global_whitelist = global_whitelist_read_int();
|
|
|
|
|
|
|
|
|
|
while(old_list)
|
|
|
|
|
{
|
|
|
|
|
entry = old_list->next;
|
|
|
|
|
NULLFREE(old_list);
|
|
|
|
|
old_list = entry;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef MODULE_SERIAL
|
|
|
|
|
static struct s_twin *twin_read_int(void)
|
|
|
|
|
{
|
|
|
|
|
FILE *fp = open_config_file(cs_twin);
|
|
|
|
|
if(!fp)
|
|
|
|
|
{ return NULL; }
|
|
|
|
|
char token[1024], str1[1024];
|
|
|
|
|
int32_t i, ret, count = 0;
|
|
|
|
|
struct s_twin *new_twin = NULL, *entry, *last = NULL;
|
|
|
|
|
|
|
|
|
|
while(fgets(token, sizeof(token), fp))
|
|
|
|
|
{
|
|
|
|
|
if(cs_strlen(token) <= 1) { continue; }
|
|
|
|
|
if(token[0] == '#' || token[0] == '/') { continue; }
|
|
|
|
|
if(cs_strlen(token) > 1024) { continue; }
|
|
|
|
|
|
|
|
|
|
for(i = 0; i < (int)cs_strlen(token); i++)
|
|
|
|
|
{
|
|
|
|
|
if((token[i] == ':' || token[i] == ' ') && token[i + 1] == ':')
|
|
|
|
|
{
|
|
|
|
|
memmove(token + i + 2, token + i + 1, cs_strlen(token) - i + 1);
|
|
|
|
|
token[i + 1] = '0';
|
|
|
|
|
}
|
|
|
|
|
if(token[i] == '#' || token[i] == '/' || token[i] == '"')
|
|
|
|
|
{
|
|
|
|
|
token[i] = '\0';
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
caid = 0;
|
|
|
|
|
uint32_t provid = 0, srvid = 0, deg = 0, freq = 0;
|
|
|
|
|
//char hdeg[4], hfreq[4], hsrvid[4];
|
|
|
|
|
memset(str1, 0, sizeof(str1));
|
|
|
|
|
|
|
|
|
|
ret = sscanf(token, "%4x:%6x:%d:%d:%d", &caid, &provid, °, &freq, &srvid);
|
|
|
|
|
if(ret < 1) { continue; }
|
|
|
|
|
|
|
|
|
|
//snprintf(hdeg, 4, "%x", deg);
|
|
|
|
|
//sscanf(hdeg, "%4x", °);
|
|
|
|
|
//snprintf(hfreq, 4, "%x", freq);
|
|
|
|
|
//sscanf(hfreq, "%4x", &freq);
|
|
|
|
|
//snprintf(hsrvid, 4, "%x", srvid);
|
|
|
|
|
//sscanf(hsrvid, "%4x", &srvid);
|
|
|
|
|
if (!cs_strncat(str1, ",", sizeof(str1))) {
|
|
|
|
|
return new_twin;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(!cs_malloc(&entry, sizeof(struct s_twin)))
|
|
|
|
|
{
|
|
|
|
|
fclose(fp);
|
|
|
|
|
return new_twin;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
count++;
|
|
|
|
|
entry->tw.caid = caid;
|
|
|
|
|
entry->tw.provid = provid;
|
|
|
|
|
entry->tw.srvid = srvid;
|
|
|
|
|
entry->tw.deg = deg;
|
|
|
|
|
entry->tw.freq = freq;
|
|
|
|
|
|
|
|
|
|
cs_debug_mask(D_TRACE, "channel: %04X:%06X:%d:%d:%d", entry->tw.caid,
|
|
|
|
|
entry->tw.provid, entry->tw.deg, entry->tw.freq, entry->tw.srvid);
|
|
|
|
|
|
|
|
|
|
if(!new_twin)
|
|
|
|
|
{
|
|
|
|
|
new_twin = entry;
|
|
|
|
|
last = new_twin;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
last->next = entry;
|
|
|
|
|
last = entry;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(count)
|
|
|
|
|
{ cs_log("%d entries read from %s", count, cs_twin); }
|
|
|
|
|
|
|
|
|
|
fclose(fp);
|
|
|
|
|
|
|
|
|
|
return new_twin;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void twin_read(void)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
struct s_twin *entry, *old_list;
|
|
|
|
|
|
|
|
|
|
old_list = cfg.twin_list;
|
|
|
|
|
cfg.twin_list = twin_read_int();
|
|
|
|
|
|
|
|
|
|
while(old_list)
|
|
|
|
|
{
|
|
|
|
|
entry = old_list->next;
|
|
|
|
|
free(old_list);
|
|
|
|
|
old_list = entry;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct ecmtw get_twin(ECM_REQUEST *er)
|
|
|
|
|
{
|
|
|
|
|
struct ecmtw tmp;
|
|
|
|
|
memset(&tmp, 0, sizeof(tmp));
|
|
|
|
|
if(!cfg.twin_list)
|
|
|
|
|
{
|
|
|
|
|
cs_log("twin_list not found!");
|
|
|
|
|
return tmp;
|
|
|
|
|
}
|
|
|
|
|
struct s_twin *entry = cfg.twin_list;
|
|
|
|
|
while(entry)
|
|
|
|
|
{
|
|
|
|
|
if(entry->tw.caid == er->caid && entry->tw.provid == er->prid && entry->tw.srvid == er->srvid)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
entry = entry->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(entry) { tmp = entry->tw; }
|
|
|
|
|
|
|
|
|
|
return (tmp);
|
|
|
|
|
}
|
|
|
|
|
#endif
|