source: trunk/module-cacheex.c@ 8459

Last change on this file since 8459 was 8459, checked in by TNe-TWo, 9 years ago

revert commit 7941
csp don't check ist beta or not
after commt 7990 is not more need
when cacheex is on while ecmd5 check first.

File size: 25.2 KB
Line 
1#include "globals.h"
2
3#ifdef CS_CACHEEX
4
5#include "cscrypt/md5.h"
6#include "module-cacheex.h"
7#include "module-cw-cycle-check.h"
8#include "oscam-chk.h"
9#include "oscam-client.h"
10#include "oscam-conf.h"
11#include "oscam-ecm.h"
12#include "oscam-lock.h"
13#include "oscam-net.h"
14#include "oscam-string.h"
15#include "oscam-time.h"
16#include "oscam-work.h"
17
18#define cs_cacheex_matcher "oscam.cacheex"
19
20extern uint8_t cc_node_id[8];
21extern uint8_t camd35_node_id[8];
22extern CS_MUTEX_LOCK ecmcache_lock;
23extern struct ecm_request_t *ecmcwcache;
24
25uint8_t cacheex_peer_id[8];
26static LLIST *invalid_cws;
27
28extern CS_MUTEX_LOCK hitcache_lock;
29struct csp_ce_hit_t *cspec_hitcache = NULL;
30uint32_t cspec_hitcache_size = 0;
31
32void cacheex_init(void) {
33 // Init random node id
34 get_random_bytes(cacheex_peer_id, 8);
35#ifdef MODULE_CCCAM
36 memcpy(cacheex_peer_id, cc_node_id, 8);
37#endif
38#ifdef MODULE_CAMD35_TCP
39 memcpy(camd35_node_id, cacheex_peer_id, 8);
40#endif
41}
42
43void cacheex_clear_account_stats(struct s_auth *account) {
44 account->cwcacheexgot = 0;
45 account->cwcacheexpush = 0;
46 account->cwcacheexhit = 0;
47}
48
49void cacheex_clear_client_stats(struct s_client *client) {
50 client->cwcacheexgot = 0;
51 client->cwcacheexpush = 0;
52 client->cwcacheexhit = 0;
53}
54
55int32_t cacheex_add_stats(struct s_client *cl, uint16_t caid, uint16_t srvid, uint32_t prid, uint8_t direction)
56{
57 if (!cfg.cacheex_enable_stats)
58 return -1;
59
60 // create list if doesn't exist
61 if (!cl->ll_cacheex_stats)
62 cl->ll_cacheex_stats = ll_create("ll_cacheex_stats");
63
64 time_t now = time((time_t*)0);
65 LL_ITER itr = ll_iter_create(cl->ll_cacheex_stats);
66 S_CACHEEX_STAT_ENTRY *cacheex_stats_entry;
67
68 // check for existing entry
69 while ((cacheex_stats_entry = ll_iter_next(&itr))) {
70 if (cacheex_stats_entry->cache_srvid == srvid &&
71 cacheex_stats_entry->cache_caid == caid &&
72 cacheex_stats_entry->cache_prid == prid &&
73 cacheex_stats_entry->cache_direction == direction) {
74 // we already have this entry - just add count and time
75 cacheex_stats_entry->cache_count++;
76 cacheex_stats_entry->cache_last = now;
77 return cacheex_stats_entry->cache_count;
78 }
79 }
80
81 // if we land here we have to add a new entry
82 if (cs_malloc(&cacheex_stats_entry, sizeof(S_CACHEEX_STAT_ENTRY))) {
83 cacheex_stats_entry->cache_caid = caid;
84 cacheex_stats_entry->cache_srvid = srvid;
85 cacheex_stats_entry->cache_prid = prid;
86 cacheex_stats_entry->cache_count = 1;
87 cacheex_stats_entry->cache_last = now;
88 cacheex_stats_entry->cache_direction = direction;
89 ll_iter_insert(&itr, cacheex_stats_entry);
90 return 1;
91 }
92 return 0;
93}
94
95
96int8_t cacheex_maxhop(struct s_client *cl)
97{
98 int maxhop = 10;
99 if (cl->reader && cl->reader->cacheex.maxhop)
100 maxhop = cl->reader->cacheex.maxhop;
101 else if (cl->account && cl->account->cacheex.maxhop)
102 maxhop = cl->account->cacheex.maxhop;
103 return maxhop;
104}
105
106static void cacheex_cache_push_to_client(struct s_client *cl, ECM_REQUEST *er)
107{
108 add_job(cl, ACTION_CACHE_PUSH_OUT, er, 0);
109}
110
111/**
112 * cacheex modes:
113 *
114 * cacheex=1 CACHE PULL:
115 * Situation: oscam A reader1 has cacheex=1, oscam B account1 has cacheex=1
116 * oscam A gets a ECM request, reader1 send this request to oscam B, oscam B checks his cache
117 * a. not found in cache: return NOK
118 * a. found in cache: return OK+CW
119 * b. not found in cache, but found pending request: wait max cacheexwaittime and check again
120 * oscam B never requests new ECMs
121 *
122 * CW-flow: B->A
123 *
124 * cacheex=2 CACHE PUSH:
125 * Situation: oscam A reader1 has cacheex=2, oscam B account1 has cacheex=2
126 * if oscam B gets a CW, its pushed to oscam A
127 * reader has normal functionality and can request ECMs
128 *
129 * Problem: oscam B can only push if oscam A is connected
130 * Problem or feature?: oscam A reader can request ecms from oscam B
131 *
132 * CW-flow: B->A
133 *
134 * cacheex=3 REVERSE CACHE PUSH:
135 * Situation: oscam A reader1 has cacheex=3, oscam B account1 has cacheex=3
136 * if oscam A gets a CW, its pushed to oscam B
137 *
138 * oscam A never requests new ECMs
139 *
140 * CW-flow: A->B
141 */
142void cacheex_cache_push(ECM_REQUEST *er)
143{
144 if (er->rc >= E_NOTFOUND && er->rc != E_UNHANDLED) //Maybe later we could support other rcs
145 return; //NOT FOUND/Invalid
146
147 if (er->cacheex_pushed || (er->ecmcacheptr && er->ecmcacheptr->cacheex_pushed))
148 return;
149
150 int64_t grp;
151 if (er->selected_reader)
152 grp = er->selected_reader->grp;
153 else
154 grp = er->grp;
155
156 //cacheex=2 mode: push (server->remote)
157 struct s_client *cl;
158 cs_readlock(&clientlist_lock);
159 for (cl=first_client->next; cl; cl=cl->next) {
160 if (er->cacheex_src != cl) {
161 if (cl->typ == 'c' && !cl->dup && cl->account && cl->account->cacheex.mode == 2) { //send cache over user
162 if (get_module(cl)->c_cache_push // cache-push able
163 && (!grp || (cl->grp & grp)) //Group-check
164 && chk_srvid(cl, er) //Service-check
165 && (chk_caid(er->caid, &cl->ctab) > 0)) //Caid-check
166 {
167 cacheex_cache_push_to_client(cl, er);
168 }
169 }
170 }
171 }
172 cs_readunlock(&clientlist_lock);
173
174 //cacheex=3 mode: reverse push (reader->server)
175
176 cs_readlock(&readerlist_lock);
177 cs_readlock(&clientlist_lock);
178
179 struct s_reader *rdr;
180 for (rdr = first_active_reader; rdr; rdr = rdr->next) {
181 cl = rdr->client;
182 if (cl && er->cacheex_src != cl && rdr->cacheex.mode == 3) { //send cache over reader
183 if (rdr->ph.c_cache_push
184 && (!grp || (rdr->grp & grp)) //Group-check
185 && chk_srvid(cl, er) //Service-check
186 && chk_ctab(er->caid, &rdr->ctab)) //Caid-check
187 {
188 cacheex_cache_push_to_client(cl, er);
189 }
190 }
191 }
192
193 cs_readunlock(&clientlist_lock);
194 cs_readunlock(&readerlist_lock);
195
196 er->cacheex_pushed = 1;
197 if (er->ecmcacheptr) er->ecmcacheptr->cacheex_pushed = 1;
198}
199
200static inline struct s_cacheex_matcher *is_cacheex_matcher_matching(ECM_REQUEST *from_er, ECM_REQUEST *to_er)
201{
202 struct s_cacheex_matcher *entry = cfg.cacheex_matcher;
203 int8_t v_ok = (from_er && to_er)?2:1;
204 while (entry) {
205 int8_t ok = 0;
206 if (from_er
207 && (!entry->caid || entry->caid == from_er->caid)
208 && (!entry->provid || entry->provid == from_er->prid)
209 && (!entry->srvid || entry->srvid == from_er->srvid)
210 && (!entry->chid || entry->chid == from_er->chid)
211 && (!entry->pid || entry->pid == from_er->pid)
212 && (!entry->ecmlen || entry->ecmlen == from_er->ecmlen))
213 ok++;
214
215 if (to_er
216 && (!entry->to_caid || entry->to_caid == to_er->caid)
217 && (!entry->to_provid || entry->to_provid == to_er->prid)
218 && (!entry->to_srvid || entry->to_srvid == to_er->srvid)
219 && (!entry->to_chid || entry->to_chid == to_er->chid)
220 && (!entry->to_pid || entry->to_pid == to_er->pid)
221 && (!entry->to_ecmlen || entry->to_ecmlen == to_er->ecmlen))
222 ok++;
223
224 if (ok == v_ok) {
225 if (!from_er || !to_er || from_er->srvid == to_er->srvid)
226 return entry;
227 }
228 entry = entry->next;
229 }
230 return NULL;
231}
232
233bool cacheex_is_match_alias(struct s_client *cl, ECM_REQUEST *er) {
234 return cl && cl->account && cl->account->cacheex.mode == 1 && is_cacheex_matcher_matching(NULL, er);
235}
236
237inline int8_t cacheex_match_alias(struct s_client *cl, ECM_REQUEST *er, ECM_REQUEST *ecm)
238{
239 if (cl && cl->account && cl->account->cacheex.mode == 1) {
240 struct s_cacheex_matcher *entry = is_cacheex_matcher_matching(ecm, er);
241 if (entry) {
242 int32_t diff = comp_timeb(&er->tps, &ecm->tps);
243 if (diff > entry->valid_from && diff < entry->valid_to) {
244#ifdef WITH_DEBUG
245 if (D_CACHEEX & cs_dblevel){
246 char result[CXM_FMT_LEN] = { 0 };
247 int32_t s, size = CXM_FMT_LEN;
248 s = ecmfmt(entry->caid, entry->provid, entry->chid, entry->pid, entry->srvid, entry->ecmlen, 0, 0, 0, result, size);
249 s += snprintf(result+s, size-s, " = ");
250 s += ecmfmt(entry->to_caid, entry->to_provid, entry->to_chid, entry->to_pid, entry->to_srvid, entry->to_ecmlen, 0, 0, 0, result+s, size-s);
251 s += snprintf(result+s, size-s, " valid %d/%d", entry->valid_from, entry->valid_to);
252 cs_debug_mask(D_CACHEEX, "cacheex-matching for: %s", result);
253 }
254#endif
255 return 1;
256 }
257 }
258 }
259 return 0;
260}
261
262static pthread_mutex_t invalid_cws_mutex = PTHREAD_MUTEX_INITIALIZER;
263
264static void add_invalid_cw(uint8_t *cw) {
265 pthread_mutex_lock(&invalid_cws_mutex);
266 if (!invalid_cws)
267 invalid_cws = ll_create("invalid cws");
268 uint8_t *cw2;
269 if (cs_malloc(&cw2, 16)) {
270 memcpy(cw2, cw, 16);
271 ll_append(invalid_cws, cw2);
272 while (ll_count(invalid_cws) > 32) {
273 ll_remove_first_data(invalid_cws);
274 }
275 }
276 pthread_mutex_unlock(&invalid_cws_mutex);
277}
278
279static int32_t is_invalid_cw(uint8_t *cw) {
280 if (!invalid_cws) return 0;
281
282 pthread_mutex_lock(&invalid_cws_mutex);
283 LL_LOCKITER *li = ll_li_create(invalid_cws, 0);
284 uint8_t *cw2;
285 int32_t invalid = 0;
286 while ((cw2 = ll_li_next(li)) && !invalid) {
287 invalid = (memcmp(cw, cw2, 16) == 0);
288 }
289 ll_li_destroy(li);
290 pthread_mutex_unlock(&invalid_cws_mutex);
291 return invalid;
292}
293
294static int32_t cacheex_add_to_cache_int(struct s_client *cl, ECM_REQUEST *er, int8_t csp)
295{
296 if (!cl)
297 return 0;
298 if (!csp && cl->reader && cl->reader->cacheex.mode!=2) { //from reader
299 cs_debug_mask(D_CACHEEX, "CACHEX received, but disabled for %s", username(cl));
300 return 0;
301 }
302 if (!csp && !cl->reader && cl->account && cl->account->cacheex.mode!=3) { //from user
303 cs_debug_mask(D_CACHEEX, "CACHEX received, but disabled for %s", username(cl));
304 return 0;
305 }
306 if (!csp && !cl->reader && !cl->account) { //not active!
307 cs_debug_mask(D_CACHEEX, "CACHEX received, but invalid client state %s", username(cl));
308 return 0;
309 }
310
311 if (er->rc < E_NOTFOUND) { //=FOUND Check CW:
312 uint8_t i, c;
313 uint8_t null=0;
314 for (i = 0; i < 16; i += 4) {
315 c = ((er->cw[i] + er->cw[i + 1] + er->cw[i + 2]) & 0xff);
316 null |= (er->cw[i] | er->cw[i + 1] | er->cw[i + 2]);
317 if (er->cw[i + 3] != c) {
318 cs_ddump_mask(D_CACHEEX, er->cw, 16, "push received cw with chksum error from %s", csp ? "csp" : username(cl));
319 cl->cwcacheexerr++;
320 if (cl->account)
321 cl->account->cwcacheexerr++;
322 return 0;
323 }
324 }
325
326 if (null==0) {
327 cs_ddump_mask(D_CACHEEX, er->cw, 16, "push received null cw from %s", csp ? "csp" : username(cl));
328 cl->cwcacheexerr++;
329 if (cl->account)
330 cl->account->cwcacheexerr++;
331 return 0;
332 }
333
334 if (is_invalid_cw(er->cw)) {
335 cs_ddump_mask(D_TRACE, er->cw, 16, "push received invalid cw from %s", csp ? "csp" : username(cl));
336 cl->cwcacheexerrcw++;
337 if (cl->account)
338 cl->account->cwcacheexerrcw++;
339 return 0;
340 }
341 }
342
343 er->grp |= cl->grp; //extend group instead overwriting, this fixes some funny not founds and timeouts when using more cacheex readers with different groups
344// er->ocaid = er->caid;
345 if (er->rc < E_NOTFOUND) //map FOUND to CACHEEX
346 er->rc = E_CACHEEX;
347 er->cacheex_src = cl;
348 er->client = NULL; //No Owner! So no fallback!
349
350 if (er->ecmlen) {
351 int32_t offset = 3;
352 if ((er->caid >> 8) == 0x17)
353 offset = 13;
354 unsigned char md5tmp[MD5_DIGEST_LENGTH];
355 memcpy(er->ecmd5, MD5(er->ecm+offset, er->ecmlen-offset, md5tmp), CS_ECMSTORESIZE);
356 cacheex_update_hash(er);
357 //csp has already initialized these hashcode
358
359 update_chid(er);
360 }
361
362 struct ecm_request_t *ecm = check_cwcache(er, cl);
363
364 add_hitcache(cl, er, ecm);
365
366// {
367// char h1[20];
368// char h2[10];
369// cs_hexdump(0, er->ecmd5, sizeof(er->ecmd5), h1, sizeof(h1));
370// cs_hexdump(0, (const uchar*)&er->csp_hash, sizeof(er->csp_hash), h2, sizeof(h2));
371// debug_ecm(D_TRACE, "cache push check %s: %s %s %s rc=%d found cache: %s", username(cl), buf, h1, h2, er->rc, ecm==NULL?"no":"yes");
372// }
373
374 if (!ecm) {
375 uint8_t cwcycle_act = cwcycle_check_act(er->caid);
376 if (er->rc < E_NOTFOUND) { // Do NOT add cacheex - not founds!
377 if (!cwcycle_act) {
378 cs_writelock(&ecmcache_lock);
379 er->next = ecmcwcache;
380 ecmcwcache = er;
381 cs_writeunlock(&ecmcache_lock);
382 }
383 er->selected_reader = cl->reader;
384
385 cacheex_cache_push(er); //cascade push!
386
387 if (er->rc < E_NOTFOUND)
388 cacheex_add_stats(cl, er->caid, er->srvid, er->prid, 1);
389
390 cl->cwcacheexgot++;
391 if (cl->account)
392 cl->account->cwcacheexgot++;
393 first_client->cwcacheexgot++;
394 if (cwcycle_act)
395 er->rc = E_NOTFOUND; //need to free
396 }
397 debug_ecm(D_CACHEEX, "got pushed %sECM %s from %s (%s)", (er->rc == E_UNHANDLED)?"request ":"", buf, csp ? "csp" : username(cl),(cwcycle_act)?"on":"off");
398
399 return er->rc < E_NOTFOUND ? 1 : 0;
400 } else {
401 if (er->rc < ecm->rc) {
402 if (ecm->csp_lastnodes == NULL) {
403 ecm->csp_lastnodes = er->csp_lastnodes;
404 er->csp_lastnodes = NULL;
405 }
406 ecm->cacheex_src = cl;
407 ecm->cacheex_pushed = 0;
408
409 write_ecm_answer(cl->reader, ecm, er->rc, er->rcEx, er->cw, ecm->msglog);
410
411 if (er->rc < E_NOTFOUND)
412 ecm->selected_reader = cl->reader;
413
414 cacheex_cache_push(ecm); //cascade push!
415
416 if (er->rc < E_NOTFOUND)
417 cacheex_add_stats(cl, er->caid, er->srvid, er->prid, 1);
418
419 cl->cwcacheexgot++;
420 if (cl->account)
421 cl->account->cwcacheexgot++;
422 first_client->cwcacheexgot++;
423
424 debug_ecm(D_CACHEEX| D_CSPCWC, "replaced pushed ECM %s from %s", buf, csp ? "csp" : username(cl));
425 } else {
426 if (er->rc < E_NOTFOUND && memcmp(er->cw, ecm->cw, sizeof(er->cw)) != 0) {
427 add_invalid_cw(ecm->cw);
428 add_invalid_cw(er->cw);
429
430 cl->cwcacheexerrcw++;
431 if (cl->account)
432 cl->account->cwcacheexerrcw++;
433
434 char cw1[16*3+2], cw2[16*3+2];
435 cs_hexdump(0, er->cw, 16, cw1, sizeof(cw1));
436 cs_hexdump(0, ecm->cw, 16, cw2, sizeof(cw2));
437
438 char ip1[20]="", ip2[20]="";
439 if (cl)
440 cs_strncpy(ip1, cs_inet_ntoa(cl->ip), sizeof(ip1));
441 if (ecm->cacheex_src)
442 cs_strncpy(ip2, cs_inet_ntoa(ecm->cacheex_src->ip), sizeof(ip2));
443 else if (ecm->selected_reader)
444 cs_strncpy(ip2, cs_inet_ntoa(ecm->selected_reader->client->ip), sizeof(ip2));
445
446 void *el = ll_has_elements(er->csp_lastnodes);
447 uint64_t node1 = el?(*(uint64_t*)el):0;
448
449 el = ll_has_elements(ecm->csp_lastnodes);
450 uint64_t node2 = el?(*(uint64_t*)el):0;
451
452 el = ll_last_element(er->csp_lastnodes);
453 uint64_t node3 = el?(*(uint64_t*)el):0;
454
455 el = ll_last_element(ecm->csp_lastnodes);
456 uint64_t node4 = el?(*(uint64_t*)el):0;
457
458 debug_ecm(D_TRACE| D_CSPCWC, "WARNING: Different CWs %s from %s(%s)<>%s(%s): %s<>%s nodes %llX %llX %llX %llX", buf,
459 csp ? "csp" : username(cl), ip1,
460 ecm->cacheex_src?username(ecm->cacheex_src):(ecm->selected_reader?ecm->selected_reader->label:"unknown/csp"), ip2,
461 cw1, cw2,
462 (long long unsigned int)node1,
463 (long long unsigned int)node2,
464 (long long unsigned int)node3,
465 (long long unsigned int)node4);
466
467 //char ecmd51[17*3];
468 //cs_hexdump(0, er->ecmd5, 16, ecmd51, sizeof(ecmd51));
469 //char csphash1[5*3];
470 //cs_hexdump(0, (void*)&er->csp_hash, 4, csphash1, sizeof(csphash1));
471 //char ecmd52[17*3];
472 //cs_hexdump(0, ecm->ecmd5, 16, ecmd52, sizeof(ecmd52));
473 //char csphash2[5*3];
474 //cs_hexdump(0, (void*)&ecm->csp_hash, 4, csphash2, sizeof(csphash2));
475 //debug_ecm(D_TRACE, "WARNING: Different CWs %s from %s<>%s: %s<>%s %s<>%s %s<>%s", buf,
476 // csp ? "csp" : username(cl),
477 // ecm->cacheex_src?username(ecm->cacheex_src):"unknown/csp",
478 // cw1, cw2,
479 // ecmd51, ecmd52,
480 // csphash1, csphash2
481 // );
482 } else {
483 debug_ecm(D_CACHEEX| D_CSPCWC, "ignored duplicate pushed ECM %s from %s", buf, csp ? "csp" : username(cl));
484 }
485 }
486 return 0;
487 }
488}
489
490void cacheex_add_to_cache(struct s_client *cl, ECM_REQUEST *er)
491{
492 if (!cacheex_add_to_cache_int(cl, er, 0))
493 free_ecm(er);
494}
495
496void cacheex_add_to_cache_from_csp(struct s_client *cl, ECM_REQUEST *er)
497{
498 if (!cacheex_add_to_cache_int(cl, er, 1))
499 free_ecm(er);
500}
501
502//Format:
503//caid:prov:srvid:pid:chid:ecmlen=caid:prov:srvid:pid:chid:ecmlen[,validfrom,validto]
504//validfrom: default=-2000
505//validto: default=4000
506//valid time if found in cache
507static struct s_cacheex_matcher *cacheex_matcher_read_int(void) {
508 FILE *fp = open_config_file(cs_cacheex_matcher);
509 if (!fp)
510 return NULL;
511
512 char token[1024];
513 unsigned char type;
514 int32_t i, ret, count=0;
515 struct s_cacheex_matcher *new_cacheex_matcher = NULL, *entry, *last=NULL;
516 uint32_t line = 0;
517
518 while (fgets(token, sizeof(token), fp)) {
519 line++;
520 if (strlen(token) <= 1) continue;
521 if (token[0]=='#' || token[0]=='/') continue;
522 if (strlen(token)>100) continue;
523
524 for (i=0;i<(int)strlen(token);i++) {
525 if ((token[i]==':' || token[i]==' ') && token[i+1]==':') {
526 memmove(token+i+2, token+i+1, strlen(token)-i+1);
527 token[i+1]='0';
528 }
529 if (token[i]=='#' || token[i]=='/') {
530 token[i]='\0';
531 break;
532 }
533 }
534
535 type = 'm';
536 uint32_t caid=0, provid=0, srvid=0, pid=0, chid=0, ecmlen=0;
537 uint32_t to_caid=0, to_provid=0, to_srvid=0, to_pid=0, to_chid=0, to_ecmlen=0;
538 int32_t valid_from=-2000, valid_to=4000;
539
540 ret = sscanf(token, "%c:%4x:%6x:%4x:%4x:%4x:%4X=%4x:%6x:%4x:%4x:%4x:%4X,%4d,%4d",
541 &type,
542 &caid, &provid, &srvid, &pid, &chid, &ecmlen,
543 &to_caid, &to_provid, &to_srvid, &to_pid, &to_chid, &to_ecmlen,
544 &valid_from, &valid_to);
545
546 type = tolower(type);
547
548 if (ret<7 || type != 'm')
549 continue;
550
551 if (!cs_malloc(&entry, sizeof(struct s_cacheex_matcher))) {
552 fclose(fp);
553 return new_cacheex_matcher;
554 }
555 count++;
556 entry->line=line;
557 entry->type=type;
558 entry->caid=caid;
559 entry->provid=provid;
560 entry->srvid=srvid;
561 entry->pid=pid;
562 entry->chid=chid;
563 entry->ecmlen=ecmlen;
564 entry->to_caid=to_caid;
565 entry->to_provid=to_provid;
566 entry->to_srvid=to_srvid;
567 entry->to_pid=to_pid;
568 entry->to_chid=to_chid;
569 entry->to_ecmlen=to_ecmlen;
570 entry->valid_from=valid_from;
571 entry->valid_to=valid_to;
572
573 cs_debug_mask(D_TRACE, "cacheex-matcher: %c: %04X:%06X:%04X:%04X:%04X:%02X = %04X:%06X:%04X:%04X:%04X:%02X valid %d/%d",
574 entry->type, entry->caid, entry->provid, entry->srvid, entry->pid, entry->chid, entry->ecmlen,
575 entry->to_caid, entry->to_provid, entry->to_srvid, entry->to_pid, entry->to_chid, entry->to_ecmlen,
576 entry->valid_from, entry->valid_to);
577
578 if (!new_cacheex_matcher) {
579 new_cacheex_matcher=entry;
580 last = new_cacheex_matcher;
581 } else {
582 last->next = entry;
583 last = entry;
584 }
585 }
586
587 if (count)
588 cs_log("%d entries read from %s", count, cs_cacheex_matcher);
589
590 fclose(fp);
591
592 return new_cacheex_matcher;
593}
594
595void cacheex_load_config_file(void) {
596 struct s_cacheex_matcher *entry, *old_list;
597
598 old_list = cfg.cacheex_matcher;
599 cfg.cacheex_matcher = cacheex_matcher_read_int();
600
601 while (old_list) {
602 entry = old_list->next;
603 free(old_list);
604 old_list = entry;
605 }
606}
607
608static int32_t cacheex_ecm_hash_calc(uchar *buf, int32_t n) {
609 int32_t i, h = 0;
610 for (i = 0; i < n; i++) {
611 h = 31 * h + buf[i];
612 }
613 return h;
614}
615
616void cacheex_update_hash(ECM_REQUEST *er) {
617 er->csp_hash = cacheex_ecm_hash_calc(er->ecm+3, er->ecmlen-3);
618}
619
620/**
621 * csp cacheex hit cache
622 **/
623
624void add_hitcache(struct s_client *cl, ECM_REQUEST *er, ECM_REQUEST *ecm) {
625 bool upd_hit = true;
626 if (!cfg.cacheex_wait_timetab.n)
627 return;
628 uint32_t cacheex_wait_time = get_cacheex_wait_time(er,NULL);
629 if (!cacheex_wait_time)
630 return;
631 if (er->rc < E_NOTFOUND) {
632
633 if (ecm){
634 struct s_reader *cl_rdr = cl->reader;
635 if (cl_rdr) {
636 struct s_reader *rdr;
637 struct s_ecm_answer *ea;
638 for(ea = ecm->matching_rdr; ea; ea = ea->next) {
639 rdr = ea->reader;
640 if (cl_rdr == rdr && cl_rdr->cacheex.mode == 2 && ((ea->status & REQUEST_ANSWERED) == REQUEST_ANSWERED)){
641 cs_debug_mask(D_CACHEEX|D_CSPCWC,"[ADD_HITCACHE] skip add self request");
642 return; //don't add hit cache, reader requested self
643 }
644 }
645 }
646
647 if (er->rc >= ecm->rc && er->rc < E_NOTFOUND && (ecm->tps.millitm - er->tps.millitm) > 0 && cacheex_wait_time) {
648 cs_debug_mask(D_CACHEEX|D_CSPCWC,"[ADD_HITCACHE] skip add too old");
649 return; //check ignored duplicate time, is over wait time don't add hit cache
650 }
651 }
652
653 cs_writelock(&hitcache_lock);
654 CSPCEHIT *ch = check_hitcache(er,cl,0);//, *ch_t = NULL;
655 if (!ch && cs_malloc(&ch, sizeof(CSPCEHIT))) {
656 upd_hit = false;
657 ch->ecmlen = er->ecmlen;
658 ch->caid = er->caid;
659 ch->prid = er->prid;
660 ch->srvid = er->srvid;
661 ch->grp = 0;
662 ch->prev = ch->next = NULL;
663 if (cspec_hitcache) {
664 cspec_hitcache->prev = ch;
665 ch->next = cspec_hitcache;
666 }
667 cspec_hitcache = ch;
668 cspec_hitcache_size++;
669 }
670 if (ch){
671 cs_debug_mask(D_CACHEEX|D_CSPCWC,"[CSPCEHIT] add_hitcache %s entry ecmlen %d caid %04X provid %06X srvid %04X grp %"PRIu64" next %s size %d", upd_hit?"upd":"add", ch->ecmlen, ch->caid, ch->prid, ch->srvid, ch->grp, (ch->next)?"Yes":"No", cspec_hitcache_size);
672 ch->grp |= er->grp;
673 ch->time = time(NULL); //always update time;
674
675 if (upd_hit && ch->prev){ //is ch->prev NULL we are top in list, no move
676 if (ch->next) {
677 ch->prev->next = ch->next;
678 ch->next->prev = ch->prev;
679 } else {
680 ch->prev->next = NULL;
681 }
682 ch->prev = NULL;
683 cspec_hitcache->prev = ch;
684 ch->next = cspec_hitcache;
685 cspec_hitcache = ch;
686 }
687
688 }
689 cs_writeunlock(&hitcache_lock);
690 }
691}
692
693struct csp_ce_hit_t *check_hitcache(ECM_REQUEST *er, struct s_client *cl, uint8_t lock) {
694 time_t now = time(NULL);
695 time_t timeout = now-cfg.max_cache_time;
696 CSPCEHIT *ch;
697 uint64_t grp = cl?cl->grp:0;
698 uint8_t fs=0;
699
700 if (lock) cs_readlock(&hitcache_lock);
701 for (ch = cspec_hitcache; ch; ch = ch->next) {
702 if (ch->time < timeout) {
703 ch = NULL;
704 break;
705 }
706 fs |= 1;
707 if (!((er->caid == ch->caid) && (er->prid == ch->prid) && (er->srvid == ch->srvid)))
708 continue;
709 fs |= 2;
710 if ((ch->ecmlen && er->ecmlen && ch->ecmlen != er->ecmlen))
711 continue;
712 if (lock) {
713 fs |= 4;
714 if ((grp && ch->grp && !(grp & ch->grp))){
715 continue;
716 }
717 } else {
718 fs |= 4;
719 }
720 fs |= 8;
721 break;
722 }
723 if (lock) cs_readunlock(&hitcache_lock);
724 if ((fs != 15) && ch) {
725 cs_log("[CSPCEHIT] check_hitcache error on check hitcache");
726 ch = NULL;
727 }
728 cs_debug_mask(D_CACHEEX| D_CSPCWC,"[CSPCEHIT] check_hitcache %s hit found max stage %d caid %04X prov %06X serv %04X grp %"PRIu64" lock %s", (fs == 15)?"yes":"no", fs, er->caid, er->prid, er->srvid, grp, lock?"yes":"no");
729 return ch;
730}
731
732void cleanup_hitcache(void) {
733 CSPCEHIT *current = NULL, *prv, *temp;
734 int32_t count = 0, mcc = cfg.max_cache_count;
735 int32_t mct = cfg.max_cache_time + (cfg.max_cache_time / 2); // 1,5
736 time_t now = time(NULL);
737
738 cs_writelock(&hitcache_lock);
739 /*for(current = cspec_hitcache, prv = NULL; current; prv=current, current = current->next, count++) {
740 cs_debug_mask(D_CACHEEX,"[CSPCEHIT] cleanup time %d ecmlen %d caid %04X provid %06X srvid %04X grp %llu count %d", (int32_t)now-current->time, current->ecmlen, current->caid, current->prid, current->srvid, current->grp, count);
741 if (count > 25)
742 break;
743 }*/
744
745 for(current = cspec_hitcache, prv = NULL; current; prv=current, current = current->next, count++) {
746 if ((now - current->time) < mct && count < mcc) { // delete old Entry to hold list small
747 continue;
748 }
749 if (prv) {
750 prv->next = NULL;
751 } else {
752 cspec_hitcache = NULL;
753 }
754 break; //we need only once, all follow to old or cache max size
755 }
756 cs_writeunlock(&hitcache_lock);
757 cspec_hitcache_size = count;
758
759 if (current)
760 cs_debug_mask(D_CACHEEX|D_CSPCWC,"[CSPCEHIT] cleanup list new size %d ct %d", cspec_hitcache_size, mct);
761
762 if (current) {
763 while (current) {
764 temp = current->next;
765 free(current);
766 current = NULL;
767 current = temp;
768 }
769 }
770}
771
772uint32_t get_cacheex_wait_time(ECM_REQUEST *er, struct s_client *cl) {
773 int32_t i,dwtime= -1,awtime=-1;
774 CSPCEHIT *ch;
775
776 for (i = 0; i < cfg.cacheex_wait_timetab.n; i++) {
777 if (i == 0 && cfg.cacheex_wait_timetab.caid[i] <= 0) {
778 dwtime = cfg.cacheex_wait_timetab.dwtime[i];
779 awtime = cfg.cacheex_wait_timetab.awtime[i];
780 continue; //check other, only valid for unset
781 }
782
783 if (cfg.cacheex_wait_timetab.caid[i] == er->caid || cfg.cacheex_wait_timetab.caid[i] == er->caid>>8 || ((cfg.cacheex_wait_timetab.cmask[i]>=0 && (er->caid & cfg.cacheex_wait_timetab.cmask[i]) == cfg.cacheex_wait_timetab.caid[i]) || cfg.cacheex_wait_timetab.caid[i] == -1)) {
784 if ((cfg.cacheex_wait_timetab.prid[i]>=0 && cfg.cacheex_wait_timetab.prid[i] == (int32_t)er->prid) || cfg.cacheex_wait_timetab.prid[i] == -1) {
785 if ((cfg.cacheex_wait_timetab.srvid[i]>=0 && cfg.cacheex_wait_timetab.srvid[i] == er->srvid) || cfg.cacheex_wait_timetab.srvid[i] == -1) {
786 dwtime = cfg.cacheex_wait_timetab.dwtime[i];
787 awtime = cfg.cacheex_wait_timetab.awtime[i];
788 break;
789 }
790 }
791
792 };
793
794 }
795 if (awtime > 0 && dwtime <= 0) {
796 return awtime;
797 }
798 if (cl == NULL) {
799 if (dwtime < 0)
800 dwtime = 0;
801 return dwtime;
802 }
803 if (awtime > 0 || dwtime > 0) {
804 //if found last in cache return dynwaittime else alwayswaittime
805 ch = check_hitcache(er,cl,1);
806 if (ch)
807 return dwtime>=awtime?dwtime:awtime;
808 else
809 return awtime>0?awtime:0;
810 }
811 return 0;
812}
813
814int32_t chk_csp_ctab(ECM_REQUEST *er, CECSPVALUETAB *tab) {
815 if (!er->caid || !tab->n)
816 return 1; // nothing setup we add all
817 int32_t i;
818 for (i = 0; i < tab->n; i++) {
819
820 if (tab->caid[i] > 0) {
821 if (tab->caid[i] == er->caid || tab->caid[i] == er->caid>>8 || ((tab->cmask[i]>=0 && (er->caid & tab->cmask[i]) == tab->caid[i]) || tab->caid[i] == -1)) {
822 if ((tab->prid[i]>=0 && tab->prid[i] == (int32_t)er->prid) || tab->prid[i] == -1) {
823 if ((tab->srvid[i]>=0 && tab->srvid[i] == er->srvid) || tab->srvid[i] == -1) {
824 return 1;
825 }
826 }
827 }
828 }
829 }
830 return 0;
831}
832
833uint8_t check_cacheex_filter(struct s_client *cl, ECM_REQUEST *er) {
834 CECSP *ce_csp = NULL;
835 uint8_t ret = 1;
836 if (cl->typ == 'c') {
837 if (cl->account && cl->account->cacheex.mode==3) {
838 ce_csp = &cl->account->cacheex;
839 }
840 } else if (cl->typ == 'p'){
841 if (cl->reader && cl->reader->cacheex.mode==2) {
842 ce_csp = &cl->reader->cacheex;
843 }
844 }
845
846 if (ce_csp) {
847 if (!chk_csp_ctab(er, &ce_csp->filter_caidtab))
848 ret = 0;
849 if (er->rc != E_FOUND && !ce_csp->allow_request)
850 ret = 0;
851 if (ce_csp->drop_csp && !checkECMD5(er))
852 ret = 0;
853 }
854 if (!ret)
855 free(er);
856 return ret;
857}
858
859#endif
Note: See TracBrowser for help on using the repository browser.