fix-vote-bug #17

Merged
mardock2009 merged 1 commits from fix-vote-bug into main 2026-02-18 00:59:02 +00:00
8 changed files with 857 additions and 760 deletions

14
config.h Executable file → Normal file
View File

@ -8,22 +8,22 @@
#define WEBIF_JQUERY 1
#define WEBIF_WIKI 1
#define WITH_COMPRESS_WEBIF 1
#define WITH_SSL 1
//#define WITH_SSL 1
#if defined(__linux__) || defined(__CYGWIN__)
#define HAVE_DVBAPI 1
#define WITH_EXTENDED_CW 1
#endif
//#define WITH_NEUTRINO 1
#define READ_SDT_CHARSETS 1
#define CLOCKFIX 1
//#define CLOCKFIX 1
#define CS_ANTICASC 1
#define WITH_DEBUG 1
#define WITH_LB 1
#define CS_CACHEEX 1
#define CS_CACHEEX_AIO 1
#define CW_CYCLE_CHECK 1
#define LCDSUPPORT 1
#define LEDSUPPORT 1
//#define LCDSUPPORT 1
//#define LEDSUPPORT 1
#define IPV6SUPPORT 1
//#define WITH_ARM_NEON 1
//#define WITH_SIGNING 1
@ -37,10 +37,10 @@
#define MODULE_CCCSHARE 1
#define MODULE_GBOX 1
#define MODULE_RADEGAST 1
#define MODULE_SERIAL 1
//#define MODULE_SERIAL 1
#define MODULE_CONSTCW 1
#define MODULE_PANDORA 1
#define MODULE_GHTTP 1
//#define MODULE_PANDORA 1
//#define MODULE_GHTTP 1
#define MODULE_SCAM 1
#define MODULE_STREAMRELAY 1

View File

@ -1045,6 +1045,7 @@ typedef struct s_cw_vote {
uint8_t cw[16];
uint8_t votes;
uint8_t local_votes;
uint8_t has_cacheex_vote; // FIX #2: flaga czy głos pochodzi z cacheex
struct s_reader *voters[MAX_VOTE_CANDIDATES];
} s_cw_vote;

View File

@ -225,6 +225,14 @@ void cwvote_caidtab_fn(const char *token, char *value, void *setting, FILE *f)
}
}
static void cwvote_local_weight_fixups_fn(void *UNUSED(var))
{
if(cfg.cwvote_local_weight < 0.0f || cfg.cwvote_local_weight > 10.0f) {
cfg.cwvote_local_weight = 1.0f;
cs_log("CW Vote: local_weight out of range (0.0-10.0), using default value 1.0");
}
}
#ifdef CS_CACHEEX
void cacheex_valuetab_fn(const char *token, char *value, void *setting, FILE *f)
{
@ -337,6 +345,7 @@ void global_fixups_fn(void *UNUSED(var))
static const struct config_list global_opts[] =
{
DEF_OPT_FIXUP_FUNC(global_fixups_fn),
DEF_OPT_FIXUP_FUNC(cwvote_local_weight_fixups_fn),
#ifdef LEDSUPPORT
DEF_OPT_INT8("enableled" , OFS(enableled) , 0),
#endif

View File

@ -1298,6 +1298,7 @@ ECM_REQUEST *get_ecmtask(void)
if(!cs_malloc(&er, sizeof(ECM_REQUEST)))
{ return NULL; }
memset(er->vote_pool, 0, sizeof(er->vote_pool)); // Initialize vote_pool to zero
er->vote_pool_session = 0; // Initialize vote session to 0
cs_ftime(&er->tps);
er->rc = E_UNHANDLED;
er->client = cl;
@ -3922,34 +3923,50 @@ int cw_vote_add(struct ecm_request_t *er, uint8_t *cw, struct s_reader *rdr)
{
int i, free_idx = -1;
int is_local = 0;
int is_cacheex = 0;
char cw_hex[33];
const char *source_label = "unknown";
// Flaga czy sprawdzać duplikaty źródła
// Dla cacheex/CSP nie sprawdzamy duplikatów - każde źródło cacheex/csp jest traktowane jako unikalne
int check_source_duplicates = 1;
if (rdr) {
source_label = rdr->label;
// Wirtualne czytniki nie są lokalne
// Wirtualne czytniki nie są lokalne - to jest cacheex lub CSP
if (rdr == virtual_cacheex_reader || rdr == virtual_csp_reader) {
is_local = 0;
is_cacheex = 1;
// Dla wirtualnych readerów nie sprawdzamy duplikatów - każdy cache jest unikalny
check_source_duplicates = 0;
} else {
is_local = is_localreader(rdr, er);
is_cacheex = cacheex_reader(rdr) ? 1 : 0;
}
} else if (er->cacheex_src) {
is_cacheex = 1;
if (check_client(er->cacheex_src) && er->cacheex_src->account) {
source_label = er->cacheex_src->account->usr;
} else {
source_label = "CACHEEX_CLIENT";
}
// Dla cacheex_src nie sprawdzamy duplikatów
check_source_duplicates = 0;
} else if (er->from_csp) {
is_cacheex = 1;
source_label = "CSP";
// Dla CSP nie sprawdzamy duplikatów
check_source_duplicates = 0;
}
cs_hexdump(0, cw, 16, cw_hex, sizeof(cw_hex));
// Sprawdź czy vote_pool jest pusta - jeśli nie, wyczyść ją
// Używamy er->tps.time jako identyfikatora sesji ECM
// Zarządzanie sesjami głosowania - używamy er->tps.time jako identyfikatora sesji ECM
// Zamiast wyczyścić całą pulę, sprawdzamy czy sesja się zmieniła i wtedy resetujemy tylko wtedy
if (er->vote_pool_session != er->tps.time) {
// Sesja się zmieniła - resetujemy pulę głosowania
memset(er->vote_pool, 0, sizeof(er->vote_pool));
er->vote_pool_session = er->tps.time;
}
@ -3962,23 +3979,50 @@ if (er->vote_pool_session != er->tps.time) {
// }
int max_cand = cfg.cwvote_max_candidates;
// Używamy konsekwentnie MIN(max_cand, MAX_VOTE_CANDIDATES) aby uniknąć overflow
int max_iter = (max_cand < MAX_VOTE_CANDIDATES) ? max_cand : MAX_VOTE_CANDIDATES;
// Sprawdź czy wpis jest poprawnie zainicjalizowany (votes > 0) i w granicach tablicy
// Porównujemy cały CW (16 bajtów), nie tylko compare_len
for (i = 0; i < max_cand; i++) {
for (i = 0; i < max_iter; i++) {
if (er->vote_pool[i].votes == 0 && free_idx < 0)
free_idx = i;
if (i < MAX_VOTE_CANDIDATES && er->vote_pool[i].votes > 0) {
if (er->vote_pool[i].votes > 0) {
int cmp = memcmp(er->vote_pool[i].cw, cw, 16);
if (cmp == 0) {
// Sprawdź unikalność źródła przed agregacją głosów
// Zapobiega wielokrotnemu głosowaniu z tego samego readera dla tego samego CW
// Dla cacheex/CSP (check_source_duplicates = 0) pomijamy to sprawdzenie
int duplicate_source = 0;
if (check_source_duplicates) {
int j;
for (j = 0; j < er->vote_pool[i].votes; j++) {
if (er->vote_pool[i].voters[j] == rdr) {
duplicate_source = 1;
break;
}
}
}
if (duplicate_source) {
// Źródło już głosowało dla tego CW - ignoruj
if (cfg.cwvote_log_enabled) {
cs_log("[Ai_vote_add] Duplicate source %s for same CW - ignoring", source_label);
}
return 0;
}
// CW już istnieje w puli - agreguj głosy niezależnie od źródła
// To pozwala na agregację głosów z różnych cacheex peerów dla tego samego CW
if (er->vote_pool[i].votes < MAX_VOTE_CANDIDATES) {
er->vote_pool[i].voters[er->vote_pool[i].votes] = rdr;
er->vote_pool[i].votes++;
if (is_local) er->vote_pool[i].local_votes++;
// FIX #2: Zapisz flagę czy głos pochodzi z cacheex
if (is_cacheex) er->vote_pool[i].has_cacheex_vote = 1;
}
// cs_log("[Ai_vote_add] Aggregated vote for existing CW → Votes: %d (local: %d) from %s",
// er->vote_pool[i].votes, er->vote_pool[i].local_votes, source_label);
@ -3996,6 +4040,7 @@ if (er->vote_pool_session != er->tps.time) {
memcpy(er->vote_pool[free_idx].cw, cw, 16);
er->vote_pool[free_idx].votes = 1;
er->vote_pool[free_idx].local_votes = is_local ? 1 : 0;
er->vote_pool[free_idx].has_cacheex_vote = is_cacheex ? 1 : 0;
// Store the actual reader if available, otherwise NULL
er->vote_pool[free_idx].voters[0] = rdr;
@ -4070,7 +4115,8 @@ int cw_vote_decide(struct ecm_request_t *er)
memcpy(er->cw, er->vote_pool[best].cw, 16);
// Update cacheex hit stats if the winning CW came from cacheex
if (cfg.cwvote_enabled && er->cacheex_src) {
// FIX #2: Używamy flagi has_cacheex_vote zamiast er->cacheex_src
if (cfg.cwvote_enabled && er->vote_pool[best].has_cacheex_vote) {
struct s_client *src_cl = er->cacheex_src;
if (src_cl && src_cl->cwcacheexhit >= 0) {
src_cl->cwcacheexhit++;
@ -4099,8 +4145,8 @@ int cw_vote_decide(struct ecm_request_t *er)
if (best >= 0) {
memcpy(er->cw, er->vote_pool[best].cw, 16);
// Update cacheex hit stats if the winning CW came from cacheex
if (cfg.cwvote_enabled && er->cacheex_src) {
// FIX #2: Używamy flagi has_cacheex_vote zamiast er->cacheex_src
if (cfg.cwvote_enabled && er->vote_pool[best].has_cacheex_vote) {
struct s_client *src_cl = er->cacheex_src;
if (src_cl && src_cl->cwcacheexhit >= 0) {
src_cl->cwcacheexhit++;
@ -4134,7 +4180,8 @@ int cw_vote_decide(struct ecm_request_t *er)
memcpy(er->cw, er->vote_pool[best].cw, 16);
// Update cacheex hit stats if the winning CW came from cacheex
if (cfg.cwvote_enabled && er->cacheex_src) {
// FIX #2: Używamy flagi has_cacheex_vote zamiast er->cacheex_src
if (cfg.cwvote_enabled && er->vote_pool[best].has_cacheex_vote) {
struct s_client *src_cl = er->cacheex_src;
if (src_cl && src_cl->cwcacheexhit >= 0) {
src_cl->cwcacheexhit++;

View File

@ -147,7 +147,7 @@
<TR><TD><A>Ai Vote Log Enabled:</A></TD><TD><input name="cwvote_log_enabled" value="0" type="hidden"><input name="cwvote_log_enabled" value="1" type="checkbox" ##CWVOTELOGENABLEDCHECKED##></TD></TR>
<TR><TD><A>Ai Vote Timeout (ms):</A></TD><TD><input name="cwvote_timeout" type="text" size="8" maxlength="8" value="##CWVOTETIMEOUT##"> <small>(default 1000)</small></TD></TR>
<TR><TD><A>Ai Vote Min Votes:</A></TD><TD><input name="cwvote_min_votes" type="text" size="4" maxlength="3" value="##CWVOTEMINVOTES##"> <small>(default min. 2)</small></TD></TR>
<TR><TD><A>Ai Vote Local Weight:</A></TD><TD><input name="cwvote_local_weight" type="text" size="5" maxlength="4" value="##CWVOTELOCALWEIGHT##"> <small>(default 2.0)</small></TD></TR>
<TR><TD><A>Ai Vote Local Weight:</A></TD><TD><input name="cwvote_local_weight" type="text" size="5" maxlength="5" value="##CWVOTELOCALWEIGHT##"> <small>(0.0-10.0, default 2.0)</small></TD></TR>
<TR><TD><A>Ai Vote Max Candidates:</A></TD><TD><input name="cwvote_max_candidates" type="text" size="4" maxlength="3" value="##CWVOTEMAXCANDIDATES##"> <small>(default 8 caution! use max 16)</small></TD></TR>
<TR><TD><A>Ai Vote Compare Length:</A></TD><TD>
<select name="cwvote_compare_len">

1498
webif/pages_wiki.c Executable file → Normal file

File diff suppressed because one or more lines are too long

12
webif/pages_wiki.h Executable file → Normal file
View File

@ -7,11 +7,13 @@
#ifdef WEBIF_WIKI
#define COMPRESSED_WIKI 1
struct wiki_entry {
const char *param;
const char *config;
const char *section;
const char *text;
uint32_t param_ofs;
uint32_t config_ofs;
uint32_t section_ofs;
uint32_t text_ofs;
int8_t status;
};
@ -19,6 +21,8 @@ int32_t wiki_count(void);
const struct wiki_entry *wiki_get_entries(void);
const char *wiki_get_help(const char *config, const char *section, const char *param);
int8_t wiki_get_status(const char *config, const char *section, const char *param);
void wiki_get_data(const char **data, size_t *data_len, size_t *data_olen);
char *wiki_get_decompressed_data(void);
void webif_wiki_prepare(void);
void webif_wiki_free(void);

Binary file not shown.