oscam-2.26.01-11942-802-wit.../module-cccam-cacheex.c

1575 lines
39 KiB
C
Raw Normal View History

#define MODULE_LOG_PREFIX "cccam"
#include "globals.h"
#include "oscam-array.h"
#if defined(CS_CACHEEX) && defined(MODULE_CCCAM)
#include "module-cacheex.h"
#include "module-cccam-data.h"
#include "module-cccam-cacheex.h"
#include "oscam-cache.h"
#include "oscam-client.h"
#include "oscam-ecm.h"
#include "oscam-string.h"
#include "oscam-chk.h"
#include "oscam-reader.h"
#ifdef CS_CACHEEX_AIO
#include "oscam-chk.h"
#include "oscam-config.h"
#endif
#define CSP_HASH_SWAP(n) (((((uint32_t)(n) & 0xFF)) << 24) | \
((((uint32_t)(n) & 0xFF00)) << 8) | \
((((uint32_t)(n) & 0xFF0000)) >> 8) | \
((((uint32_t)(n) & 0xFF000000)) >> 24))
extern int32_t cc_cli_connect(struct s_client *cl);
extern int32_t cc_cmd_send(struct s_client *cl, uint8_t *buf, int32_t len, cc_msg_type_t cmd);
#ifdef CS_CACHEEX_AIO
void cc_cacheex_feature_trigger_in(struct s_client *cl, uint8_t *buf)
{
int32_t feature = 0;
int i = 0;
uint8_t filter_count;
uint8_t j, k, l, rc;
feature = buf[1] | (buf[0] << 8);
FTAB *lgonly_tab;
// check client & cacheex-mode
if(
!check_client(cl) ||
!(
(cl->typ == 'c' && cl->account->cacheex.mode > 0) ||
(cl->typ == 'p' && cl->reader->cacheex.mode > 0)
)
)
{
return;
}
switch(feature)
{
// set localgenerated only
case 1:
if(cl->typ == 'c' && (cl->account->cacheex.mode == 2 || cl->account->cacheex.mode == 1))
{
if(cfg.cacheex_lg_only_remote_settings || cl->account->cacheex.lg_only_remote_settings)
cl->account->cacheex.localgenerated_only = buf[4];
else if(buf[4])
cl->account->cacheex.localgenerated_only = buf[4];
}
else if(cl->typ == 'p' && cl->reader->cacheex.mode == 3)
{
if(cfg.cacheex_lg_only_remote_settings || cl->reader->cacheex.lg_only_remote_settings)
cl->reader->cacheex.localgenerated_only = buf[4];
else if(buf[4])
cl->reader->cacheex.localgenerated_only = buf[4];
}
break;
// set localgenerated only caidtab
case 2:
filter_count = buf[i+4];
i += 5;
memset(&lgonly_tab, 0, sizeof(lgonly_tab));
if(cl->typ == 'c' && (cl->account->cacheex.mode == 2 || cl->account->cacheex.mode == 1))
{
lgonly_tab = &cl->account->cacheex.lg_only_tab;
}
else if(cl->typ == 'p' && cl->reader->cacheex.mode == 3)
{
lgonly_tab = &cl->reader->cacheex.lg_only_tab;
}
else
{
return;
}
// remotesettings enabled - replace local settings
if(cfg.cacheex_lg_only_remote_settings ||
(
(cl->typ == 'c' && (cl->account->cacheex.mode == 2 || cl->account->cacheex.mode == 1) && cl->account->cacheex.lg_only_remote_settings)
|| (cl->typ == 'p' && cl->reader->cacheex.mode == 3 && cl->reader->cacheex.lg_only_remote_settings)
)
)
{
ftab_clear(lgonly_tab);
for(j = 0; j < filter_count; j++)
{
FILTER d;
memset(&d, 0, sizeof(d));
d.caid = b2i(2, buf + i);
i += 2;
d.nprids = 1;
d.prids[0] = NO_PROVID_VALUE;
ftab_add(lgonly_tab, &d);
}
}
// remotesettings disabled - write additional remote-caids received
else
{
for(j = 0; j < filter_count; j++)
{
FILTER d;
memset(&d, 0, sizeof(d));
d.caid = b2i(2, buf + i);
i += 2;
d.nprids = 1;
d.prids[0] = NO_PROVID_VALUE;
if(!chk_lg_only_cp(d.caid, d.prids[0], lgonly_tab))
{
cs_log_dbg(D_CACHEEX, "%04X:%06X not found in local settings - adding them", d.caid, d.prids[0]);
for(l = rc = 0; (!rc) && (l < lgonly_tab->nfilts); l++)
{
if(lgonly_tab->filts[l].caid == d.caid)
{
rc = 1;
if(lgonly_tab->filts[l].nprids+1 <= CS_MAXPROV)
{
lgonly_tab->filts[l].prids[lgonly_tab->filts[l].nprids] = d.prids[0];
lgonly_tab->filts[l].nprids++;
}
else
{
cs_log_dbg(D_CACHEEX, "error: cacheex_lg_only_tab -> max. number(%i) of providers reached", CS_MAXPROV);
}
}
}
if(!rc)
{
ftab_add(lgonly_tab, &d);
}
}
}
}
break;
// set cacheex_ecm_filter - extended
case 4:
filter_count = buf[i+4];
i += 5;
CECSPVALUETAB *filter;
memset(&filter, 0, sizeof(filter));
if(cl->typ == 'c' && (cl->account->cacheex.mode == 2 || cl->account->cacheex.mode == 1) && cl->account->cacheex.allow_filter)
{
filter = &cl->account->cacheex.filter_caidtab;
}
else if(cl->typ == 'p' && cl->reader->cacheex.mode == 3 && cl->reader->cacheex.allow_filter)
{
filter = &cl->reader->cacheex.filter_caidtab;
}
else
{
return;
}
cecspvaluetab_clear(filter);
for(j = 0; j < filter_count; j++)
{
int32_t caid = -1, cmask = -1, provid = -1, srvid = -1;
CECSPVALUETAB_DATA d;
memset(&d, 0, sizeof(d));
caid = b2i(2, buf + i);
if(caid == 0xFFFF) caid = -1;
i += 2;
cmask = b2i(2, buf + i);
if(cmask == 0xFFFF) cmask = -1;
i += 2;
provid = b2i(3, buf + i);
if(provid == 0xFFFFFF) provid = -1;
i += 3;
srvid = b2i(2, buf + i);
if(srvid == 0xFFFF) srvid = -1;
i += 2;
if(caid > 0)
{
d.caid = caid;
d.cmask = cmask;
d.prid = provid;
d.srvid = srvid;
cecspvaluetab_add(filter, &d);
}
}
break;
// no push after
case 8: ;
CAIDVALUETAB *ctab;
memset(&ctab, 0, sizeof(ctab));
if(cl->typ == 'c' && (cl->account->cacheex.mode == 2 || cl->account->cacheex.mode == 1))
{
ctab = &cl->account->cacheex.cacheex_nopushafter_tab;
}
else if(cl->typ == 'p' && cl->reader->cacheex.mode == 3)
{
ctab = &cl->reader->cacheex.cacheex_nopushafter_tab;
}
else
{
return;
}
filter_count = buf[i+4];
i += 5;
caidvaluetab_clear(ctab);
for(j = 0; j < filter_count; j++)
{
uint16_t caid = 0, value = 0;
CAIDVALUETAB_DATA d;
memset(&d, 0, sizeof(d));
caid = b2i(2, buf + i);
if(caid == 0xFFFF) caid = -1;
i += 2;
value = b2i(2, buf + i);
if(value == 0xFFFF) value = -1;
i += 2;
if(caid > 0)
{
d.caid = caid;
d.value = value;
caidvaluetab_add(ctab, &d);
}
}
break;
// max_hop
case 16:
if(cl->typ == 'c' && (cl->account->cacheex.mode == 2 || cl->account->cacheex.mode == 1) && cl->account->cacheex.allow_maxhop)
{
cl->account->cacheex.maxhop = buf[4];
cl->account->cacheex.maxhop_lg = buf[5];
}
else if(cl->typ == 'p' && cl->reader->cacheex.mode == 3 && cl->reader->cacheex.allow_maxhop)
{
cl->reader->cacheex.maxhop = buf[4];
cl->reader->cacheex.maxhop_lg = buf[5];
}
break;
// aio-version
case 32: ;
uint16_t payload_size = b2i(2, buf + i + 2);
if(cl->typ == 'c' && cl->account->cacheex.mode > 0)
{
char *ofs = (char *)buf + i + 4;
memset(cl->account->cacheex.aio_version, 0, sizeof(cl->account->cacheex.aio_version));
if(payload_size > 0)
{
size_t str_len = strnlen(ofs, payload_size);
if(str_len >= sizeof(cl->account->cacheex.aio_version))
str_len = sizeof(cl->account->cacheex.aio_version) - 1;
memcpy(cl->account->cacheex.aio_version, ofs, str_len);
// sanitize: remove non-printable characters
size_t x;
for(x = 0; x < str_len; x++)
{
if(cl->account->cacheex.aio_version[x] < 0x20 || cl->account->cacheex.aio_version[x] > 0x7E)
{
cl->account->cacheex.aio_version[x] = '\0';
break;
}
}
}
}
else if(cl->typ == 'p' && cl->reader->cacheex.mode > 0)
{
char *ofs = (char *)buf + i + 4;
memset(cl->reader->cacheex.aio_version, 0, sizeof(cl->reader->cacheex.aio_version));
if(payload_size > 0)
{
size_t str_len = strnlen(ofs, payload_size);
if(str_len >= sizeof(cl->reader->cacheex.aio_version))
str_len = sizeof(cl->reader->cacheex.aio_version) - 1;
memcpy(cl->reader->cacheex.aio_version, ofs, str_len);
// sanitize: remove non-printable characters
size_t x;
for(x = 0; x < str_len; x++)
{
if(cl->reader->cacheex.aio_version[x] < 0x20 || cl->reader->cacheex.aio_version[x] > 0x7E)
{
cl->reader->cacheex.aio_version[x] = '\0';
break;
}
}
}
}
break;
// lg_only_tab caid:prov1[,provN][;caid:prov]
case 64: ;
memset(&lgonly_tab, 0, sizeof(lgonly_tab));
if(cl->typ == 'c' && (cl->account->cacheex.mode == 2 || cl->account->cacheex.mode == 1))
{
lgonly_tab = &cl->account->cacheex.lg_only_tab;
}
else if(cl->typ == 'p' && cl->reader->cacheex.mode == 3)
{
lgonly_tab = &cl->reader->cacheex.lg_only_tab;
}
else
{
return;
}
filter_count = buf[i+4];
i += 5;
// remotesettings enabled - replace local settings
if(cfg.cacheex_lg_only_remote_settings ||
(
(cl->typ == 'c' && (cl->account->cacheex.mode == 2 || cl->account->cacheex.mode == 1) && cl->account->cacheex.lg_only_remote_settings)
|| (cl->typ == 'p' && cl->reader->cacheex.mode == 3 && cl->reader->cacheex.lg_only_remote_settings)
|| !lgonly_tab->nfilts
)
)
{
ftab_clear(lgonly_tab);
for(j = 0; j < filter_count; j++)
{
FILTER d;
memset(&d, 0, sizeof(d));
d.caid = b2i(2, buf + i);
i += 2;
d.nprids = b2i(1, buf + i);
i += 1;
for(k=0; k < d.nprids; k++)
{
d.prids[k] = b2i(3, buf + i);
i += 3;
}
ftab_add(lgonly_tab, &d);
}
}
// remotesettings disabled - write additional remote-caid/provids received
else
{
for(j = 0; j < filter_count; j++)
{
FILTER d;
memset(&d, 0, sizeof(d));
d.caid = b2i(2, buf + i);
i += 2;
d.nprids = b2i(1, buf + i);
i += 1;
for(k=0; k < d.nprids; k++)
{
d.prids[k] = b2i(3, buf + i);
i += 3;
if(!chk_ident_filter(d.caid, d.prids[k], lgonly_tab))
{
cs_log_dbg(D_CACHEEX, "%04X:%06X not found in local settings - adding them", d.caid, d.prids[k]);
for(l = rc = 0; (!rc) && (l < lgonly_tab->nfilts); l++)
{
if(lgonly_tab->filts[l].caid == d.caid)
{
rc = 1;
if(lgonly_tab->filts[l].nprids+1 <= CS_MAXPROV)
{
lgonly_tab->filts[l].prids[lgonly_tab->filts[l].nprids] = d.prids[k];
lgonly_tab->filts[l].nprids++;
}
else
{
cs_log_dbg(D_CACHEEX, "error: cacheex_lg_only_tab -> max. number of providers reached");
}
}
}
if(!rc)
{
ftab_add(lgonly_tab, &d);
}
}
}
}
}
break;
default:
return;
}
}
void cc_cacheex_feature_trigger(struct s_client *cl, int32_t feature, uint8_t mode)
{
// size: (feature-bitfield & mask: 2) + payload-size: 2 + feature-payload :x
uint16_t size = 2 + 2;
int i = 0;
uint8_t j;
uint8_t payload[MAX_ECM_SIZE-size];
memset(payload, 0, sizeof(payload));
// check client & cacheex-mode
if(!check_client(cl))
{
return;
}
switch(feature)
{
FTAB *lgonly_tab;
// set localgenerated only
case 1:
// bitfield
i2b_buf(2, feature, payload + i);
i += 2;
// payload-size
i2b_buf(2, 1, payload + i);
i += 2;
size += 1;
// set payload
if(mode == 2)
{
if(cl->reader->cacheex.localgenerated_only_in)
payload[i] = cl->reader->cacheex.localgenerated_only_in;
else
payload[i] = cfg.cacheex_localgenerated_only_in;
}
else if(mode == 3)
{
if(cl->account->cacheex.localgenerated_only_in)
payload[i] = cl->account->cacheex.localgenerated_only_in;
else
payload[i] = cfg.cacheex_localgenerated_only_in;
}
break;
// set localgenerated only caidtab; cx-aio < 9.2.6-04
case 2: ;
if(mode == 2)
{
lgonly_tab = &cl->reader->cacheex.lg_only_in_tab;
if(!lgonly_tab->nfilts)
lgonly_tab = &cfg.cacheex_lg_only_in_tab;
}
else if(mode == 3)
{
lgonly_tab = &cl->account->cacheex.lg_only_in_tab;
if(!lgonly_tab->nfilts)
lgonly_tab = &cfg.cacheex_lg_only_in_tab;
}
else
{
return;
}
size += (lgonly_tab->nfilts * 2 + 1);
if(size < 32)
size = 32;
// bitfield
i2b_buf(2, feature, payload + i);
i += 2;
// payload-size
if((lgonly_tab->nfilts * 2 + 1) > (int)sizeof(payload))
{
cs_log_dbg(D_CACHEEX, "ERROR: too much localgenerated only caidtab-entries (max. 255)");
return;
}
i2b_buf(2, (lgonly_tab->nfilts * 2 + 1), payload + i); // n * caid + ctnum
i += 2;
// set payload
if(lgonly_tab->nfilts > 255)
{
cs_log_dbg(D_CACHEEX, "ERROR: too much localgenerated only caidtab-entries (max. 255)");
return;
}
payload[i] = lgonly_tab->nfilts;
i += 1;
for(j = 0; j < lgonly_tab->nfilts; j++)
{
FILTER *d = &lgonly_tab->filts[j];
if(d->caid)
{
i2b_buf(2, d->caid, payload + i);
i += 2;
}
else
{
continue;
}
}
break;
// cacchex_ecm_filter extendend
case 4: ;
CECSPVALUETAB *filter;
if(mode == 2)
{
filter = &cl->reader->cacheex.filter_caidtab;
// if not set, use global settings
if(cl->reader->cacheex.filter_caidtab.cevnum == 0 && cfg.cacheex_filter_caidtab.cevnum > 0)
filter = &cfg.cacheex_filter_caidtab;
// if aio, use global aio settings
if(cl->reader->cacheex.filter_caidtab.cevnum == 0 && cfg.cacheex_filter_caidtab_aio.cevnum > 0 && cl->cacheex_aio_checked && (cl->reader->cacheex.feature_bitfield & 4))
filter = &cfg.cacheex_filter_caidtab_aio;
}
else if(mode == 3)
{
filter = &cl->account->cacheex.filter_caidtab;
// if not set, use global settings
if(cl->account->cacheex.filter_caidtab.cevnum == 0 && cfg.cacheex_filter_caidtab.cevnum > 0)
filter = &cfg.cacheex_filter_caidtab;
// if aio, use global aio settings
if(cl->account->cacheex.filter_caidtab.cevnum == 0 && cfg.cacheex_filter_caidtab_aio.cevnum > 0 && cl->cacheex_aio_checked && (cl->account->cacheex.feature_bitfield & 4))
filter = &cfg.cacheex_filter_caidtab_aio;
}
else
{
return;
}
size += (filter->cevnum * 9 + 1);
// bitfield
i2b_buf(2, feature, payload + i);
i += 2;
// payload-size
if((filter->cevnum * 9 + 1) > (int)sizeof(payload))
{
cs_log_dbg(D_CACHEEX, "ERROR: to much cacheex_ecm_filter-entries (max. 63), only 30 default cccam-filters sent");
return;
}
i2b_buf(2, (filter->cevnum * 9 + 1), payload + i); // n * (caid2,mask2,provid3,srvid2) + ctnum1
i += 2;
// set payload
payload[i] = filter->cevnum;
i += 1;
for(j = 0; j < filter->cevnum; j++)
{
CECSPVALUETAB_DATA *d = &filter->cevdata[j];
if(d->caid)
{
i2b_buf(2, d->caid, payload + i);
i += 2;
}
if(d->cmask)
{
i2b_buf(2, d->cmask, payload + i);
}
i += 2;
if(d->prid)
{
i2b_buf(3, d->prid, payload + i);
}
i += 3;
if(d->srvid)
{
i2b_buf(2, d->srvid, payload + i);
}
i += 2;
}
break;
// no push after
case 8: ;
CAIDVALUETAB *ctab;
if(mode == 2)
{
ctab = &cl->reader->cacheex.cacheex_nopushafter_tab;
if(!ctab->cvnum)
ctab = &cfg.cacheex_nopushafter_tab;
}
else if(mode == 3)
{
ctab = &cl->account->cacheex.cacheex_nopushafter_tab;
if(!ctab->cvnum)
ctab = &cfg.cacheex_nopushafter_tab;
}
else
{
return;
}
size += (ctab->cvnum * 4 + 1);
// bitfield
i2b_buf(2, feature, payload + i);
i += 2;
// payload-size
if((ctab->cvnum * 4 + 1) > (int)sizeof(payload))
{
cs_log_dbg(D_CACHEEX, "ERROR: to much no push after caidtvalueab-entries (max. 255)");
return;
}
i2b_buf(2, (ctab->cvnum * 4 + 1), payload + i); // n * (caid2+value2) + cvnum
i += 2;
// set payload
if(ctab->cvnum > 255)
{
cs_log_dbg(D_CACHEEX, "ERROR: to much no push after caidtvalueab-entries (max. 255)");
return;
}
payload[i] = ctab->cvnum;
i += 1;
for(j = 0; j < ctab->cvnum; j++)
{
CAIDVALUETAB_DATA *d = &ctab->cvdata[j];
if(d->caid)
{
i2b_buf(2, d->caid, payload + i);
i += 2;
i2b_buf(2, d->value, payload + i);
i += 2;
}
else
{
continue;
}
}
break;
// max hop
case 16:
// bitfield
i2b_buf(2, feature, payload + i);
i += 2;
// payload-size
i2b_buf(2, 2, payload + i);
i += 2;
size += 2;
// set payload
if(mode == 2)
{
if(cl->reader->cacheex.maxhop)
payload[i] = cl->reader->cacheex.maxhop;
else
payload[i] = 0;
i += 1;
if(cl->reader->cacheex.maxhop_lg)
payload[i] = cl->reader->cacheex.maxhop_lg;
else
payload[i] = 0;
}
else if(mode == 3)
{
if(cl->account->cacheex.maxhop)
payload[i] = cl->account->cacheex.maxhop;
else
payload[i] = 0;
i += 1;
if(cl->account->cacheex.maxhop_lg)
payload[i] = cl->account->cacheex.maxhop_lg;
else
payload[i] = 0;
}
break;
// aio-version
case 32: ;
uint8_t token[CS_AIO_VERSION_LEN];
memset(token, 0, sizeof(token));
// bitfield
i2b_buf(2, feature, payload + i);
i += 2;
// payload-size
i2b_buf(2, sizeof(token), payload + i);
i += 2;
size +=sizeof(token);
// set payload
snprintf((char *)token, sizeof(token), "%s", CS_AIO_VERSION);
uint8_t *ofs = payload + i;
memcpy(ofs, token, sizeof(token));
break;
// lg_only_tab
case 64: ;
// bitfield
i2b_buf(2, feature, payload + i);
i += 2;
if(mode == 2)
{
lgonly_tab = &cl->reader->cacheex.lg_only_in_tab;
if(!lgonly_tab->nfilts)
lgonly_tab = &cfg.cacheex_lg_only_in_tab;
}
else if(mode == 3)
{
lgonly_tab = &cl->account->cacheex.lg_only_in_tab;
if(!lgonly_tab->nfilts)
lgonly_tab = &cfg.cacheex_lg_only_in_tab;
}
else
{
return;
}
char *cx_aio_ftab;
cx_aio_ftab = cxaio_ftab_to_buf(lgonly_tab);
if(cs_strlen(cx_aio_ftab) > 0 && cx_aio_ftab[0] != '\0')
{
size += cs_strlen(cx_aio_ftab) * sizeof(char);
// payload-size
i2b_buf(2, cs_strlen(cx_aio_ftab), payload + i);
i += 2;
// filter counter
payload[i] = lgonly_tab->nfilts;
i += 1;
for(j=0; j<cs_strlen(cx_aio_ftab); j+=2)
{
payload[i] = (gethexval(cx_aio_ftab[j]) << 4) | gethexval(cx_aio_ftab[j + 1]);
i++;
}
}
if(size < 32)
size = 32;
NULLFREE(cx_aio_ftab);
break;
default:
return;
}
uint8_t buf[size];
memset(buf, 0, sizeof(buf));
memcpy(buf, payload, size);
cc_cmd_send(cl, payload, size, MSG_CACHE_FEATURE_TRIGGER);
}
void cc_cacheex_feature_request_save(struct s_client *cl, uint8_t *buf)
{
int32_t field = b2i(2, buf);
if(cl->typ == 'c' && (cl->account->cacheex.mode == 2 ||cl->account->cacheex.mode == 1))
{
cl->account->cacheex.feature_bitfield = field;
// flag 32 => aio-version
if(cl->account->cacheex.feature_bitfield & 32)
{
cc_cacheex_feature_trigger(cl, 32, 2);
}
}
if(cl->typ == 'p' && cl->reader->cacheex.mode == 3)
{
cl->reader->cacheex.feature_bitfield = field;
// flag 32 => aio-version
if(cl->reader->cacheex.feature_bitfield & 32)
{
cc_cacheex_feature_trigger(cl, 32, 3);
}
}
if(cl->typ == 'c' && cl->account->cacheex.mode == 3)
{
struct s_auth *acc = cl->account;
if(acc)
{
acc->cacheex.feature_bitfield = field;
// process feature-specific actions based on feature_bitfield received
// flag 1 => set localgenerated only flag
if(acc->cacheex.feature_bitfield & 1)
{
cc_cacheex_feature_trigger(cl, 1, 3);
}
// flag 2 => set localgenerated only caids flag
if(acc->cacheex.feature_bitfield & 2 && !(acc->cacheex.feature_bitfield & 64))
{
cc_cacheex_feature_trigger(cl, 2, 3);
}
// flag 4 => set cacheex_ecm_filter (extended)
if(acc->cacheex.feature_bitfield & 4)
{
cc_cacheex_feature_trigger(cl, 4, 3);
}
// flag 8 => np push after caids
if(acc->cacheex.feature_bitfield & 8)
{
cc_cacheex_feature_trigger(cl, 8, 3);
}
// flag 16 => maxhop
if(acc->cacheex.feature_bitfield & 16)
{
cc_cacheex_feature_trigger(cl, 16, 3);
}
// flag 32 => aio-version
if(acc->cacheex.feature_bitfield & 32)
{
cc_cacheex_feature_trigger(cl, 32, 3);
}
// flag 64 => lg_only_tab
if(acc->cacheex.feature_bitfield & 64)
{
cc_cacheex_feature_trigger(cl, 64, 3);
}
}
else
{
cs_log_dbg(D_CACHEEX, "feature_bitfield save failed - cl, %s", username(cl));
}
}
else if(cl->typ == 'p' && (cl->reader->cacheex.mode == 2 || cl->reader->cacheex.mode == 1))
{
struct s_reader *rdr = cl->reader;
if(rdr)
{
rdr->cacheex.feature_bitfield = field;
// process feature-specific actions
// flag 1 => set localgenerated_only; cause of rdr->cacheex.localgenerated_only_in is set
if(rdr->cacheex.feature_bitfield & 1)
{
cc_cacheex_feature_trigger(cl, 1, 2);
}
// flag 2 => set localgenerated_only_caidtab; cause of rdr->cacheex.localgenerated_only_in_caidtab is set
if(rdr->cacheex.feature_bitfield & 2 && !(rdr->cacheex.feature_bitfield & 64))
{
cc_cacheex_feature_trigger(cl, 2, 2);
}
// flag 4 => set cacchex_ecm_filter extendend
if(rdr->cacheex.feature_bitfield & 4)
{
cc_cacheex_feature_trigger(cl, 4, 2);
}
// flag 8 => np push after caids
if(rdr->cacheex.feature_bitfield & 8)
{
cc_cacheex_feature_trigger(cl, 8, 2);
}
// flag 16 => maxhop
if(rdr->cacheex.feature_bitfield & 16)
{
cc_cacheex_feature_trigger(cl, 16, 2);
}
// flag 32 => aio-version
if(rdr->cacheex.feature_bitfield & 32)
{
cc_cacheex_feature_trigger(cl, 32, 2);
}
// flag 64 => lg_only_tab
if(rdr->cacheex.feature_bitfield & 64)
{
cc_cacheex_feature_trigger(cl, 64, 2);
}
}
else
{
cs_log_dbg(D_CACHEEX, "feature_bitfield save failed - rdr, %s", username(cl));
}
}
}
void cc_cacheex_feature_request_reply(struct s_client *cl)
{
int32_t size = 2;
uint8_t rbuf[size];
i2b_buf(2, CACHEEX_FEATURES, rbuf);
cc_cmd_send(cl, rbuf, size, MSG_CACHE_FEATURE_EXCHANGE_REPLY);
}
void cc_cacheex_feature_request(struct s_client *cl)
{
int32_t size = 2;
uint8_t rbuf[2];
i2b_buf(2, CACHEEX_FEATURES, rbuf);
cc_cmd_send(cl, rbuf, size, MSG_CACHE_FEATURE_EXCHANGE);
}
#endif
void cc_cacheex_filter_out(struct s_client *cl)
{
struct s_reader *rdr = (cl->typ == 'c') ? NULL : cl->reader;
int i = 0, j;
CECSPVALUETAB *filter;
int32_t size = 482; // minimal size, keep it <= 512 for max UDP packet size without fragmentation
uint8_t buf[482];
memset(buf, 0, sizeof(buf));
if(rdr && (rdr->cacheex.mode == 2
#ifdef CS_CACHEEX_AIO
|| rdr->cacheex.mode == 1
#endif
)) // mode == 2 send filters from rdr
{
filter = &rdr->cacheex.filter_caidtab;
#ifdef CS_CACHEEX_AIO
// if not set, use global settings
if(rdr->cacheex.filter_caidtab.cevnum == 0 && cfg.cacheex_filter_caidtab.cevnum > 0)
filter = &cfg.cacheex_filter_caidtab;
#endif
}
else if(cl->typ == 'c' && cl->account && cl->account->cacheex.mode == 3) // mode == 3 send filters from acc
{
filter = &cl->account->cacheex.filter_caidtab;
#ifdef CS_CACHEEX_AIO
// if not set, use global settings
if(cl->account->cacheex.filter_caidtab.cevnum == 0 && cfg.cacheex_filter_caidtab.cevnum > 0)
filter = &cfg.cacheex_filter_caidtab;
#endif
}
else
{
return;
}
i2b_buf(2, filter->cevnum, buf + i);
i += 2;
int32_t max_filters = 30;
for(j = 0; j < max_filters; j++)
{
if(filter->cevnum > j)
{
CECSPVALUETAB_DATA *d = &filter->cevdata[j];
i2b_buf(4, d->caid, buf + i);
}
i += 4;
}
for(j = 0; j < max_filters; j++)
{
if(filter->cevnum > j)
{
CECSPVALUETAB_DATA *d = &filter->cevdata[j];
i2b_buf(4, d->cmask, buf + i);
}
i += 4;
}
for(j = 0; j < max_filters; j++)
{
if(filter->cevnum > j)
{
CECSPVALUETAB_DATA *d = &filter->cevdata[j];
i2b_buf(4, d->prid, buf + i);
}
i += 4;
}
for(j = 0; j < max_filters; j++)
{
if(filter->cevnum > j)
{
CECSPVALUETAB_DATA *d = &filter->cevdata[j];
i2b_buf(4, d->srvid, buf + i);
}
i += 4;
}
cs_log_dbg(D_CACHEEX, "cacheex: sending push filter request to %s", username(cl));
cc_cmd_send(cl, buf, size, MSG_CACHE_FILTER);
}
void cc_cacheex_filter_in(struct s_client *cl, uint8_t *buf)
{
struct s_reader *rdr = (cl->typ == 'c') ? NULL : cl->reader;
int i = 0, j;
int32_t caid, cmask, provid, srvid;
CECSPVALUETAB *filter;
// mode == 2 write filters to acc
if(cl->typ == 'c' && cl->account && (cl->account->cacheex.mode == 2
#ifdef CS_CACHEEX_AIO
|| cl->account->cacheex.mode == 1
#endif
) && cl->account->cacheex.allow_filter == 1)
{
filter = &cl->account->cacheex.filter_caidtab;
}
else if(rdr && rdr->cacheex.mode == 3 && rdr->cacheex.allow_filter == 1) // mode == 3 write filters to rdr
{
filter = &rdr->cacheex.filter_caidtab;
}
else
{
return;
}
cecspvaluetab_clear(filter);
i += 2;
int32_t max_filters = 30;
for(j = 0; j < max_filters; j++)
{
caid = b2i(4, buf + i);
if(caid > 0)
{
CECSPVALUETAB_DATA d;
memset(&d, 0, sizeof(d));
d.caid = b2i(4, buf + i);
cecspvaluetab_add(filter, &d);
}
i += 4;
}
for(j = 0; j < max_filters; j++)
{
cmask = b2i(4, buf + i);
if(j < filter->cevnum)
{
CECSPVALUETAB_DATA *d = &filter->cevdata[j];
d->cmask = cmask;
}
i += 4;
}
for(j = 0; j < max_filters; j++)
{
provid = b2i(4, buf + i);
if(j < filter->cevnum)
{
CECSPVALUETAB_DATA *d = &filter->cevdata[j];
d->prid = provid;
}
i += 4;
}
for(j = 0; j < max_filters; j++)
{
srvid = b2i(4, buf + i);
if(j < filter->cevnum)
{
CECSPVALUETAB_DATA *d = &filter->cevdata[j];
d->srvid = srvid;
}
i += 4;
}
cs_log_dbg(D_CACHEEX, "cacheex: received push filter request from %s", username(cl));
}
static int32_t cc_cacheex_push_chk(struct s_client *cl, struct ecm_request_t *er)
{
struct cc_data *cc = cl->cc;
if(chk_is_null_nodeid(cc->peer_node_id))
{
cs_log_dbg(D_CACHEEX, "cacheex: NO peer_node_id got yet, skip!");
return 0;
}
if(
2026-02-17 09:41:05 +00:00
ll_count(er->csp_lastnodes) >= cacheex_maxhop(cl, er) // check max 10 nodes to push
#ifdef CS_CACHEEX_AIO
2026-02-17 09:41:05 +00:00
&& (!er->localgenerated || (er->localgenerated && (ll_count(er->csp_lastnodes) >= cacheex_maxhop_lg(cl, er)))) // check maxhop_lg if cw is lg-flagged
#endif
)
{
#ifdef CS_CACHEEX_AIO
2026-02-17 09:41:05 +00:00
cs_log_dbg(D_CACHEEX, "cacheex: nodelist reached %d nodes(non-lg) or reached %d nodes(lg), no push", cacheex_maxhop(cl, er), cacheex_maxhop_lg(cl, er));
#else
2026-02-17 09:41:05 +00:00
cs_log_dbg(D_CACHEEX, "cacheex: nodelist reached %d nodes, no push", cacheex_maxhop(cl, er));
#endif
return 0;
}
uint8_t *remote_node = cc->peer_node_id;
// search existing peer nodes
LL_LOCKITER *li = ll_li_create(er->csp_lastnodes, 0);
uint8_t *node;
while((node = ll_li_next(li)))
{
cs_log_dbg(D_CACHEEX, "cacheex: check node %" PRIu64 "X == %" PRIu64 "X ?",
cacheex_node_id(node), cacheex_node_id(remote_node));
if(memcmp(node, remote_node, 8) == 0)
{
break;
}
}
ll_li_destroy(li);
// node found, so we got it from there, do not push
if(node)
{
cs_log_dbg(D_CACHEEX, "cacheex: node %" PRIu64 "X found in list => skip push!", cacheex_node_id(node));
return 0;
}
if(!cl->cc)
{
if(cl->reader && !cl->reader->tcp_connected)
{
cc_cli_connect(cl);
}
}
if(!cc || !cl->udp_fd)
{
cs_log_dbg(D_CACHEEX, "cacheex: not connected %s -> no push", username(cl));
return 0;
}
// check if cw is already pushed
if(check_is_pushed(er->cw_cache, cl))
{
return 0;
}
return 1;
}
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) +
#ifdef CS_CACHEEX_AIO
(ll_count(er->csp_lastnodes) + 1) * 8 + sizeof(uint8_t);
#else
(ll_count(er->csp_lastnodes) + 1) * 8;
#endif
uint8_t *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, CSP_HASH_SWAP(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);
#ifdef CS_CACHEEX_AIO
// add localgenerated cw-flag
if(er->localgenerated)
{
*ofs = 1;
}
else
{
*ofs = 0xFF;
}
#endif
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;
}
void cc_cacheex_push_in(struct s_client *cl, uint8_t *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;
}
}
#ifndef CS_CACHEEX_AIO
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);
}
#endif
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;
}
#ifdef CS_CACHEEX_AIO
// check cacheex_ecm_filter
if(check_client(cl) && cl->typ == 'p' && cl->reader && cl->reader->cacheex.mode == 2
&& ( (cl->reader->cacheex.filter_caidtab.cevnum > 0 && !chk_csp_ctab(er, &cl->reader->cacheex.filter_caidtab)) // reader cacheex_ecm_filter not matching if set
|| (cl->reader->cacheex.filter_caidtab.cevnum == 0 && (cl->reader->cacheex.feature_bitfield & 4) && cfg.cacheex_filter_caidtab_aio.cevnum > 0 && !chk_csp_ctab(er, &cfg.cacheex_filter_caidtab_aio)) // global cacheex_ecm_filter_aio not matching if set
|| (cl->reader->cacheex.filter_caidtab.cevnum == 0 && cfg.cacheex_filter_caidtab_aio.cevnum == 0 && cfg.cacheex_filter_caidtab.cevnum > 0 && !chk_csp_ctab(er, &cfg.cacheex_filter_caidtab)) // global cacheex_ecm_filter not matching if set
)
)
{
cs_log_dbg(D_CACHEEX, "cacheex: received cache not matching cacheex_ecm_filter => pushing filter again");
cc_cacheex_filter_out(cl); // get cache != cacheex_ecm_filter, send filter again - remote restarted
if(cl->reader->cacheex.feature_bitfield & 4)
cc_cacheex_feature_trigger(cl, 4, 2);
free_push_in_ecm(er);
return;
}
if(check_client(cl) && cl->typ == 'c' && cl->account && cl->account->cacheex.mode == 3
&& ( (cl->account->cacheex.filter_caidtab.cevnum > 0 && !chk_csp_ctab(er, &cl->account->cacheex.filter_caidtab)) // account cacheex_ecm_filter not matching if set
|| (cl->account->cacheex.filter_caidtab.cevnum == 0 && (cl->account->cacheex.feature_bitfield & 4) && cfg.cacheex_filter_caidtab_aio.cevnum > 0 && !chk_csp_ctab(er, &cfg.cacheex_filter_caidtab_aio)) // global cacheex_ecm_filter_aio not matching if set
|| (cl->account->cacheex.filter_caidtab.cevnum == 0 && cfg.cacheex_filter_caidtab_aio.cevnum == 0 && cfg.cacheex_filter_caidtab.cevnum > 0 && !chk_csp_ctab(er, &cfg.cacheex_filter_caidtab)) // global cacheex_ecm_filter not matching if set
)
)
{
cs_log_dbg(D_CACHEEX, "cacheex: received cache not matching cacheex_ecm_filter => pushing filter again");
cc_cacheex_filter_out(cl); // get cache != cacheex_ecm_filter, send filter again - remote restarted
if(cl->account->cacheex.feature_bitfield & 4)
cc_cacheex_feature_trigger(cl, 4, 3);
free_push_in_ecm(er);
return;
}
#endif
// Read csp_hash
er->csp_hash = CSP_HASH_SWAP(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++;
#ifndef CS_CACHEEX_AIO
// check max nodes
2026-02-17 09:41:05 +00:00
if(count > cacheex_maxhop(cl, er))
{
cs_log_dbg(D_CACHEEX, "cacheex: received %d nodes (max=%d), ignored! %s",
2026-02-17 09:41:05 +00:00
(int32_t)count, cacheex_maxhop(cl, er), username(cl));
NULLFREE(er);
return;
}
#endif
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));
}
#ifdef CS_CACHEEX_AIO
if(b2i(1, ofs) == 1)
{
er->localgenerated = 1;
cs_log_dbg(D_CACHEEX, "cacheex: received ECM with localgenerated flag %04X@%06X:%04X %s", er->caid, er->prid, er->srvid, username(cl));
//check max nodes for lg flagged cw:
2026-02-17 09:41:05 +00:00
if(ll_count(er->csp_lastnodes) > cacheex_maxhop_lg(cl, er))
{
2026-02-17 09:41:05 +00:00
cs_log_dbg(D_CACHEEX, "cacheex: received (lg) %d nodes (max=%d), ignored! %s", ll_count(er->csp_lastnodes), cacheex_maxhop_lg(cl, er), username(cl));
free_push_in_ecm(er);
return;
}
}
// without localgenerated flag
else
{
//check max nodes:
2026-02-17 09:41:05 +00:00
if(ll_count(er->csp_lastnodes) > cacheex_maxhop(cl, er))
{
2026-02-17 09:41:05 +00:00
cs_log_dbg(D_CACHEEX, "cacheex: received %d nodes (max=%d), ignored! %s", ll_count(er->csp_lastnodes), cacheex_maxhop(cl, er), username(cl));
free_push_in_ecm(er);
return;
}
if(
(cl->typ == 'p' && cl->reader && cl->reader->cacheex.mode == 2 && !chk_srvid_localgenerated_only_exception(er) // cx2
&& (
// !aio
(cl->cacheex_aio_checked && !cl->reader->cacheex.feature_bitfield
&& (
!cfg.cacheex_lg_only_in_aio_only && !cl->reader->cacheex.lg_only_in_aio_only
&& (cfg.cacheex_localgenerated_only_in || cl->reader->cacheex.localgenerated_only_in || ((cl->reader->cacheex.feature_bitfield & 64) && (chk_lg_only(er, &cl->reader->cacheex.lg_only_in_tab) || chk_lg_only(er, &cfg.cacheex_lg_only_in_tab))) || ( !(cl->reader->cacheex.feature_bitfield & 64) && (chk_ctab_ex(er->caid, &cl->reader->cacheex.localgenerated_only_in_caidtab) || chk_ctab_ex(er->caid, &cfg.cacheex_localgenerated_only_in_caidtab))))
)
)
||
// aio
(cl->cacheex_aio_checked && cl->reader->cacheex.feature_bitfield
&& (
cfg.cacheex_localgenerated_only_in || cl->reader->cacheex.localgenerated_only_in || ((cl->reader->cacheex.feature_bitfield & 64) && (chk_lg_only(er, &cl->reader->cacheex.lg_only_in_tab) || chk_lg_only(er, &cfg.cacheex_lg_only_in_tab))) || ( !(cl->reader->cacheex.feature_bitfield & 64) && (chk_ctab_ex(er->caid, &cl->reader->cacheex.localgenerated_only_in_caidtab) || chk_ctab_ex(er->caid, &cfg.cacheex_localgenerated_only_in_caidtab)))
)
)
)
)
||
(cl->typ == 'c' && cl->account && cl->account->cacheex.mode == 3 && !chk_srvid_localgenerated_only_exception(er) // cx3
&& (
// !aio
(cl->cacheex_aio_checked && !cl->account->cacheex.feature_bitfield
&& (
!cfg.cacheex_lg_only_in_aio_only && !cl->account->cacheex.lg_only_in_aio_only
&& (cfg.cacheex_localgenerated_only_in || cl->account->cacheex.localgenerated_only_in || ((cl->account->cacheex.feature_bitfield & 64) && (chk_lg_only(er, &cl->account->cacheex.lg_only_in_tab) || chk_lg_only(er, &cfg.cacheex_lg_only_in_tab))) || ( !(cl->account->cacheex.feature_bitfield & 64) && (chk_ctab_ex(er->caid, &cl->account->cacheex.localgenerated_only_in_caidtab) || chk_ctab_ex(er->caid, &cfg.cacheex_localgenerated_only_in_caidtab))))
)
)
||
// aio
(cl->cacheex_aio_checked && cl->account->cacheex.feature_bitfield
&& (
cfg.cacheex_localgenerated_only_in || cl->account->cacheex.localgenerated_only_in || ((cl->account->cacheex.feature_bitfield & 64) && (chk_lg_only(er, &cl->account->cacheex.lg_only_in_tab) || chk_lg_only(er, &cfg.cacheex_lg_only_in_tab))) || ( !(cl->account->cacheex.feature_bitfield & 64) && (chk_ctab_ex(er->caid, &cl->account->cacheex.localgenerated_only_in_caidtab) || chk_ctab_ex(er->caid, &cfg.cacheex_localgenerated_only_in_caidtab)))
)
)
)
)
)
{
cs_log_dbg(D_CACHEEX, "cacheex: drop ECM without localgenerated flag %04X@%06X:%04X %s", er->caid, er->prid, er->srvid, username(cl));
free_push_in_ecm(er);
return;
}
}
#endif
// 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));
}
#ifdef CS_CACHEEX_AIO
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);
}
#endif
cacheex_add_to_cache(cl, er);
}
void cc_cacheex_module_init(struct s_module *ph)
{
ph->c_cache_push = cc_cacheex_push_out;
ph->c_cache_push_chk = cc_cacheex_push_chk;
}
#endif