Attempt to count descramblers used properly
[oscam.git] / oscam-cache.c
blob8ae01765884ba68b91d9ec58dfbdbc535964ca26
1 #define MODULE_LOG_PREFIX "cache"
3 #include "globals.h"
4 #include "module-cacheex.h"
5 #include "module-cw-cycle-check.h"
6 #include "oscam-cache.h"
7 #include "oscam-chk.h"
8 #include "oscam-client.h"
9 #include "oscam-ecm.h"
10 #include "oscam-garbage.h"
11 #include "oscam-lock.h"
12 #include "oscam-net.h"
13 #include "oscam-string.h"
14 #include "oscam-time.h"
15 #include "oscam-hashtable.h"
18 // CACHE functions **************************************************************+
19 struct s_pushclient
21 struct s_client *cl;
22 struct s_pushclient *next_push;
25 typedef struct cw_t
27 uint8_t cw[16];
28 uint8_t odd_even; // odd/even byte (0x80 0x81)
29 uint8_t cwc_cycletime;
30 uint8_t cwc_next_cw_cycle;
31 uint8_t got_bad_cwc; // used by cycle check
32 uint16_t caid; // first caid received
33 uint32_t prid; // first prid received
34 uint16_t srvid; // first srvid received
35 struct s_reader *selected_reader; // first answering: reader
36 struct s_client *cacheex_src; // first answering: cacheex client
37 uint64_t grp; // updated grp
38 uint8_t csp; // updated if answer from csp
39 uint8_t cacheex; // updated if answer from cacheex
40 uint8_t localcards; // updated if answer from local cards (or proxy using localcards option)
41 uint8_t proxy; // updated if answer from local reader
42 uint32_t count; // count of same cws receved
43 // for push out
44 pthread_rwlock_t pushout_client_lock;
45 struct s_pushclient *pushout_client; // list of clients that pushing cw
46 // end push out
47 node ht_node; // node for hash table
48 node ll_node; // node for linked list
49 } CW;
51 typedef struct cache_t
53 hash_table ht_cw;
54 list ll_cw;
55 struct timeb upd_time; // updated time. Update time at each cw got
56 struct timeb first_recv_time; // time of first cw received
57 uint32_t csp_hash;
58 node ht_node; // node for hash table
59 node ll_node; // node for linked list
60 } ECMHASH;
62 static pthread_rwlock_t cache_lock;
63 static hash_table ht_cache;
64 static list ll_cache;
65 static int8_t cache_init_done = 0;
67 void init_cache(void)
69 init_hash_table(&ht_cache, &ll_cache);
70 if (pthread_rwlock_init(&cache_lock,NULL) != 0)
71 { cs_log("Error creating lock cache_lock!"); }
72 else
73 { cache_init_done = 1; }
76 void free_cache(void)
78 cleanup_cache(true);
79 cache_init_done = 0;
80 deinitialize_hash_table(&ht_cache);
81 pthread_rwlock_destroy(&cache_lock);
84 uint32_t cache_size(void)
86 if(!cache_init_done)
87 { return 0; }
89 return count_hash_table(&ht_cache);
92 static uint8_t count_sort(CW *a, CW *b)
94 if (a->count == b->count) return 0;
95 return (a->count > b->count) ? -1 : 1; // DESC order by count
98 uint8_t check_is_pushed(void *cwp, struct s_client *cl)
100 struct s_pushclient *cl_tmp;
101 CW* cw = (CW*)cwp;
102 bool pushed=false;
104 SAFE_RWLOCK_RDLOCK(&cw->pushout_client_lock);
105 for (cl_tmp = cw->pushout_client; cl_tmp; cl_tmp = cl_tmp->next_push)
107 if(cl_tmp->cl==cl)
109 pushed=true;
110 break;
114 if(!pushed)
116 SAFE_RWLOCK_UNLOCK(&cw->pushout_client_lock);
117 SAFE_RWLOCK_WRLOCK(&cw->pushout_client_lock);
119 struct s_pushclient *new_push_client;
120 if(cs_malloc(&new_push_client, sizeof(struct s_pushclient)))
122 new_push_client->cl=cl;
124 new_push_client->next_push=cw->pushout_client;
125 cw->pushout_client=new_push_client;
128 SAFE_RWLOCK_UNLOCK(&cw->pushout_client_lock);
129 return 0;
131 else
133 SAFE_RWLOCK_UNLOCK(&cw->pushout_client_lock);
134 return 1;
138 uint8_t get_odd_even(ECM_REQUEST *er)
140 return (er->ecm[0] != 0x80 && er->ecm[0] != 0x81 ? 0 : er->ecm[0]);
144 CW *get_first_cw(ECMHASH *ecmhash, ECM_REQUEST *er)
146 if(!ecmhash) return NULL;
148 node *j;
149 CW *cw;
151 j = get_first_node_list(&ecmhash->ll_cw);
152 while (j) {
153 cw = get_data_from_node(j);
155 if(cw && cw->odd_even == get_odd_even(er) && !cw->got_bad_cwc)
156 return cw;
158 j = j->next;
161 return NULL;
164 static int compare_csp_hash(const void *arg, const void *obj)
166 uint32_t h = ((const ECMHASH*)obj)->csp_hash;
167 return memcmp(arg, &h, 4);
170 static int compare_cw(const void *arg, const void *obj)
172 return memcmp(arg, ((const CW*)obj)->cw, 16);
175 static bool cwcycle_check_cache(struct s_client *cl, ECM_REQUEST *er, CW *cw)
177 (void)cl; (void)er; (void)cw;
179 #ifdef CW_CYCLE_CHECK
180 if(cw->got_bad_cwc)
181 return 0;
183 uint8_t cwc_ct = cw->cwc_cycletime > 0 ? cw->cwc_cycletime : 0;
184 uint8_t cwc_ncwc = cw->cwc_next_cw_cycle < 2 ? cw->cwc_next_cw_cycle : 2;
185 if(checkcwcycle(cl, er, NULL, cw->cw, 0, cwc_ct, cwc_ncwc) != 0)
187 cs_log_dbg(D_CWC | D_LB, "{client %s, caid %04X, srvid %04X} [check_cache] cyclecheck passed ecm in INT. cache.", (cl ? cl->account->usr : "-"), er->caid, er->srvid);
189 else
191 cs_log_dbg(D_CWC, "cyclecheck [BAD CW Cycle] from Int. Cache detected.. {client %s, caid %04X, srvid %04X} [check_cache] -> skip cache answer", (cl ? cl->account->usr : "-"), er->caid, er->srvid);
192 cw->got_bad_cwc = 1; // no need to check it again
193 return 0;
195 #endif
196 return 1;
200 * This function returns cw (mostly received) in cache for er, or NULL if not found.
201 * IMPORTANT:
202 * - If found, DON'T forget to free returned ecm, because it is a copy useful to get data
203 * - If found, and cacheex_src client of returned ecm is not NULL, and we want to access it,
204 * remember to check for its validity (client structure is still existent)
205 * E.g.: if(ecm->cacheex_src && is_valid_client(ecm->cacheex_src) && !ecm->cacheex_src->kill)
206 * We don't want make this stuff here to avoid useless cpu time if outside function we would not access to it.
208 struct ecm_request_t *check_cache(ECM_REQUEST *er, struct s_client *cl)
210 if(!cache_init_done || !er->csp_hash) return NULL;
212 ECM_REQUEST *ecm = NULL;
213 ECMHASH *result;
214 CW *cw;
215 uint64_t grp = cl?cl->grp:0;
217 SAFE_RWLOCK_RDLOCK(&cache_lock);
219 result = find_hash_table(&ht_cache, &er->csp_hash, sizeof(uint32_t),&compare_csp_hash);
220 cw = get_first_cw(result, er);
221 if (!cw)
222 goto out_err;
224 if(cw->csp // csp have no grp!
225 || !grp // csp client(no grp) searching for cache
226 || (grp && cw->grp // ecm group --> only when readers/ex-clients answer (e_found) it
227 && (grp & cw->grp)))
229 #ifdef CS_CACHEEX
230 //if preferlocalcards=2 for this ecm request, we can server ONLY cw from localcards readers until stage<3
231 if(er->preferlocalcards==2 && !cw->localcards && er->stage<3){
232 goto out_err;
235 CWCHECK check_cw = get_cwcheck(er);
237 if((!cw->proxy && !cw->localcards) // cw received from ONLY cacheex/csp peers
238 && check_cw.counter>1
239 && cw->count < check_cw.counter
240 && (check_cw.mode || !er->cacheex_wait_time_expired))
242 goto out_err;
244 #endif
246 if (!cwcycle_check_cache(cl, er, cw))
247 goto out_err;
249 if (cs_malloc(&ecm, sizeof(ECM_REQUEST)))
251 ecm->rc = E_FOUND;
252 ecm->rcEx = 0;
253 memcpy(ecm->cw, cw->cw, 16);
254 ecm->grp = cw->grp;
255 ecm->selected_reader = cw->selected_reader;
256 ecm->cwc_cycletime = cw->cwc_cycletime;
257 ecm->cwc_next_cw_cycle = cw->cwc_next_cw_cycle;
258 ecm->cacheex_src = cw->cacheex_src;
259 ecm->cw_count = cw->count;
263 out_err:
264 SAFE_RWLOCK_UNLOCK(&cache_lock);
265 return ecm;
268 static void cacheex_cache_add(ECM_REQUEST *er, ECMHASH *result, CW *cw, bool add_new_cw)
270 (void)er; (void)result; (void)cw; (void)add_new_cw;
271 #ifdef CS_CACHEEX
272 er->cw_cache = cw;
273 cacheex_cache_push(er);
275 // cacheex debug log lines and cw diff stuff
276 if(!check_client(er->cacheex_src))
277 return;
279 if(!add_new_cw)
281 debug_ecm(D_CACHEEX| D_CSP, "got duplicate pushed ECM %s from %s", buf, er->from_csp ? "csp" : username(er->cacheex_src));
282 return;
285 debug_ecm(D_CACHEEX|D_CSP, "got pushed ECM %s from %s", buf, er->from_csp ? "csp" : username(er->cacheex_src));
286 CW *cw_first = get_first_cw(result, er);
287 if(!cw_first)
288 return;
290 // compare er cw with mostly counted cached cw
291 if(memcmp(er->cw, cw_first->cw, sizeof(er->cw)) != 0)
293 er->cacheex_src->cwcacheexerrcw++;
294 if (er->cacheex_src->account)
295 er->cacheex_src->account->cwcacheexerrcw++;
297 if (((0x0200| 0x0800) & cs_dblevel)) // avoid useless operations if debug is not enabled
299 char cw1[16*3+2], cw2[16*3+2];
300 cs_hexdump(0, er->cw, 16, cw1, sizeof(cw1));
301 cs_hexdump(0, cw_first->cw, 16, cw2, sizeof(cw2));
303 char ip1[20]="", ip2[20]="";
304 if (check_client(er->cacheex_src))
305 cs_strncpy(ip1, cs_inet_ntoa(er->cacheex_src->ip), sizeof(ip1));
306 if (check_client(cw_first->cacheex_src))
307 cs_strncpy(ip2, cs_inet_ntoa(cw_first->cacheex_src->ip), sizeof(ip2));
308 else if (cw_first->selected_reader && check_client(cw_first->selected_reader->client))
309 cs_strncpy(ip2, cs_inet_ntoa(cw_first->selected_reader->client->ip), sizeof(ip2));
311 debug_ecm(D_CACHEEX| D_CSP, "WARNING: Different CWs %s from %s(%s)<>%s(%s): %s<>%s ", buf,
312 er->from_csp ? "csp" : username(er->cacheex_src), ip1,
313 check_client(cw_first->cacheex_src)?username(cw_first->cacheex_src):(cw_first->selected_reader?cw_first->selected_reader->label:"unknown/csp"), ip2,
314 cw1, cw2);
317 #endif
320 void add_cache(ECM_REQUEST *er)
322 if(!cache_init_done || !er->csp_hash) return;
324 ECMHASH *result = NULL;
325 CW *cw = NULL;
326 bool add_new_cw=false;
328 SAFE_RWLOCK_WRLOCK(&cache_lock);
330 // add csp_hash to cache
331 result = find_hash_table(&ht_cache, &er->csp_hash, sizeof(uint32_t), &compare_csp_hash);
332 if(!result){
333 if(cs_malloc(&result, sizeof(ECMHASH))){
334 result->csp_hash = er->csp_hash;
335 init_hash_table(&result->ht_cw, &result->ll_cw);
336 cs_ftime(&result->first_recv_time);
338 add_hash_table(&ht_cache, &result->ht_node, &ll_cache, &result->ll_node, result, &result->csp_hash, sizeof(uint32_t));
340 }else{
341 SAFE_RWLOCK_UNLOCK(&cache_lock);
342 cs_log("ERROR: NO added HASH to cache!!");
343 return;
347 cs_ftime(&result->upd_time); // need to be updated at each cw! We use it for deleting this hash when no more cws arrive inside max_cache_time!
349 //add cw to this csp hash
350 cw = find_hash_table(&result->ht_cw, er->cw, sizeof(er->cw), &compare_cw);
352 if(!cw)
354 if(count_hash_table(&result->ht_cw) >= 10) // max 10 different cws stored
356 SAFE_RWLOCK_UNLOCK(&cache_lock);
357 return;
360 while(1)
362 if(cs_malloc(&cw, sizeof(CW)))
364 memcpy(cw->cw, er->cw, sizeof(er->cw));
365 cw->odd_even = get_odd_even(er);
366 cw->cwc_cycletime = er->cwc_cycletime;
367 cw->cwc_next_cw_cycle = er->cwc_next_cw_cycle;
368 cw->count= 0;
369 cw->csp = 0;
370 cw->cacheex = 0;
371 cw->localcards=0;
372 cw->proxy=0;
373 cw->grp = 0;
374 cw->caid = er->caid;
375 cw->prid = er->prid;
376 cw->srvid = er->srvid;
377 cw->selected_reader=er->selected_reader;
378 cw->cacheex_src=er->cacheex_src;
379 cw->pushout_client = NULL;
381 while(1)
383 if (pthread_rwlock_init(&cw->pushout_client_lock, NULL) == 0)
384 break;
386 cs_log("Error creating lock pushout_client_lock!");
387 cs_sleepms(1);
390 add_hash_table(&result->ht_cw, &cw->ht_node, &result->ll_cw, &cw->ll_node, cw, cw->cw, sizeof(er->cw));
391 add_new_cw=true;
392 break;
395 cs_log("ERROR: NO added CW to cache!! Re-trying...");
396 cs_sleepms(1);
400 // update if answered from csp/cacheex/local_proxy
401 if(er->from_cacheex) cw->cacheex = 1;
402 if(er->from_csp) cw->csp = 1;
403 if(!er->cacheex_src)
405 if(is_localreader(er->selected_reader, er)) cw->localcards=1;
406 else cw->proxy = 1;
409 // always update group and counter
410 cw->grp |= er->grp;
411 cw->count++;
413 // sort cw_list by counter (DESC order)
414 if(cw->count>1)
415 sort_list(&result->ll_cw, count_sort);
417 SAFE_RWLOCK_UNLOCK(&cache_lock);
419 cacheex_cache_add(er, result, cw, add_new_cw);
422 void cleanup_cache(bool force)
424 ECMHASH *ecmhash;
425 CW *cw;
426 struct s_pushclient *pc, *nxt;
427 node *i,*i_next,*j,*j_next;
429 struct timeb now;
430 int64_t gone_first, gone_upd;
432 if(!cache_init_done)
433 { return; }
435 SAFE_RWLOCK_WRLOCK(&cache_lock);
437 i = get_first_node_list(&ll_cache);
438 while(i)
440 i_next = i->next;
441 ecmhash = get_data_from_node(i);
443 if(!ecmhash)
445 i = i_next;
446 continue;
449 cs_ftime(&now);
450 gone_first = comp_timeb(&now, &ecmhash->first_recv_time);
451 gone_upd = comp_timeb(&now, &ecmhash->upd_time);
453 if(!force && gone_first<=(cfg.max_cache_time*1000)) // not continue, useless check for nexts one!
455 break;
458 if(force || gone_upd>(cfg.max_cache_time*1000))
460 j = get_first_node_list(&ecmhash->ll_cw);
461 while(j)
463 j_next = j->next;
464 cw = get_data_from_node(j);
465 if(cw)
467 pthread_rwlock_destroy(&cw->pushout_client_lock);
468 pc = cw->pushout_client;
469 cw->pushout_client=NULL;
470 while(pc)
472 nxt = pc->next_push;
473 NULLFREE(pc);
474 pc = nxt;
476 remove_elem_list(&ecmhash->ll_cw, &cw->ll_node);
477 remove_elem_hash_table(&ecmhash->ht_cw, &cw->ht_node);
478 NULLFREE(cw);
480 j = j_next;
483 deinitialize_hash_table(&ecmhash->ht_cw);
484 remove_elem_list(&ll_cache, &ecmhash->ll_node);
485 remove_elem_hash_table(&ht_cache, &ecmhash->ht_node);
486 NULLFREE(ecmhash);
488 i = i_next;
490 SAFE_RWLOCK_UNLOCK(&cache_lock);