From d76a2b2171223d5102e19656674fddbbfc3c75fe Mon Sep 17 00:00:00 2001 From: mardock2009 Date: Wed, 18 Feb 2026 00:56:00 +0000 Subject: [PATCH] fix-vote-bug --- config.h | 14 +- globals.h | 1 + oscam-config-global.c | 9 + oscam-ecm.c | 81 ++- webif/config/global.html | 2 +- webif/pages_wiki.c | 1498 +++++++++++++++++++------------------- webif/pages_wiki.h | 12 +- webif/wiki_gen | Bin 35200 -> 35320 bytes 8 files changed, 857 insertions(+), 760 deletions(-) mode change 100755 => 100644 config.h mode change 100755 => 100644 webif/pages_wiki.c mode change 100755 => 100644 webif/pages_wiki.h diff --git a/config.h b/config.h old mode 100755 new mode 100644 index 4f47e8d..0660d54 --- a/config.h +++ b/config.h @@ -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 diff --git a/globals.h b/globals.h index b9f5046..28d0674 100755 --- a/globals.h +++ b/globals.h @@ -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; diff --git a/oscam-config-global.c b/oscam-config-global.c index 001417c..73b3d14 100755 --- a/oscam-config-global.c +++ b/oscam-config-global.c @@ -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 diff --git a/oscam-ecm.c b/oscam-ecm.c index 8e68dfa..7107a8f 100755 --- a/oscam-ecm.c +++ b/oscam-ecm.c @@ -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++; @@ -4133,17 +4179,18 @@ int cw_vote_decide(struct ecm_request_t *er) if (has_majority || (timeout_reached && fallback == 1)) { 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) { - struct s_client *src_cl = er->cacheex_src; - if (src_cl && src_cl->cwcacheexhit >= 0) { - src_cl->cwcacheexhit++; - if (src_cl->account) { - src_cl->account->cwcacheexhit++; - } - first_client->cwcacheexhit++; + // Update cacheex hit stats if the winning CW came from cacheex + // 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++; + if (src_cl->account) { + src_cl->account->cwcacheexhit++; } + first_client->cwcacheexhit++; } + } if (cfg.cwvote_log_enabled) { cs_hexdump(0, er->cw, 16, cw_hex, sizeof(cw_hex)); diff --git a/webif/config/global.html b/webif/config/global.html index 140b232..ac3f374 100755 --- a/webif/config/global.html +++ b/webif/config/global.html @@ -147,7 +147,7 @@ Ai Vote Log Enabled: Ai Vote Timeout (ms): (default 1000) Ai Vote Min Votes: (default min. 2) - Ai Vote Local Weight: (default 2.0) + Ai Vote Local Weight: (0.0-10.0, default 2.0) Ai Vote Max Candidates: (default 8 caution! use max 16) Ai Vote Compare Length: