1 #define MODULE_LOG_PREFIX "cacheex"
7 #include "cscrypt/md5.h"
8 #include "module-cacheex.h"
9 #include "module-cw-cycle-check.h"
10 #include "oscam-cache.h"
11 #include "oscam-chk.h"
12 #include "oscam-client.h"
13 #include "oscam-conf.h"
14 #include "oscam-ecm.h"
15 #include "oscam-hashtable.h"
16 #include "oscam-lock.h"
17 #include "oscam-net.h"
18 #include "oscam-string.h"
19 #include "oscam-time.h"
20 #include "oscam-work.h"
22 #define cs_cacheex_matcher "oscam.cacheex"
24 extern uint8_t cc_node_id
[8];
25 extern uint8_t camd35_node_id
[8];
27 uint8_t cacheex_peer_id
[8];
29 extern CS_MUTEX_LOCK ecm_pushed_deleted_lock
;
30 extern struct ecm_request_t
*ecm_pushed_deleted
;
31 extern CS_MUTEX_LOCK ecmcache_lock
;
32 extern struct ecm_request_t
*ecmcwcache
;
34 // HIT CACHE functions **************************************************************
36 typedef struct hit_key_t
{
42 typedef struct cache_hit_t
{
45 struct timeb max_hitcache_time
;
47 uint64_t grp_last_max_hitcache_time
;
52 static pthread_rwlock_t hitcache_lock
;
53 static hash_table ht_hitcache
;
54 static list ll_hitcache
;
55 static bool cacheex_running
;
57 void cacheex_init_hitcache(void)
59 init_hash_table(&ht_hitcache
, &ll_hitcache
);
60 if (pthread_rwlock_init(&hitcache_lock
,NULL
) != 0)
61 cs_log("Error creating lock hitcache_lock!");
62 cacheex_running
= true;
65 void cacheex_free_hitcache(void)
67 cacheex_running
= false;
68 cacheex_cleanup_hitcache(true);
69 deinitialize_hash_table(&ht_hitcache
);
70 pthread_rwlock_destroy(&hitcache_lock
);
73 static int cacheex_compare_hitkey(const void *arg
, const void *obj
)
75 if(((const HIT_KEY
*)arg
)->caid
==((const CACHE_HIT
*)obj
)->key
.caid
76 && ((const HIT_KEY
*)arg
)->prid
==((const CACHE_HIT
*)obj
)->key
.prid
77 && ((const HIT_KEY
*)arg
)->srvid
==((const CACHE_HIT
*)obj
)->key
.srvid
)
84 static int32_t cacheex_check_hitcache(ECM_REQUEST
*er
, struct s_client
*cl
)
88 memset(&search
, 0, sizeof(HIT_KEY
));
89 search
.caid
= er
->caid
;
90 search
.prid
= er
->prid
;
91 search
.srvid
= er
->srvid
;
92 SAFE_RWLOCK_RDLOCK(&hitcache_lock
);
93 result
= find_hash_table(&ht_hitcache
, &search
, sizeof(HIT_KEY
), &cacheex_compare_hitkey
);
97 int64_t gone
= comp_timeb(&now
, &result
->time
);
98 uint64_t grp
= cl
?cl
->grp
:0;
101 gone
<= (cfg
.max_hitcache_time
*1000)
103 (!grp
|| !result
->grp
|| (grp
& result
->grp
))
106 SAFE_RWLOCK_UNLOCK(&hitcache_lock
);
110 SAFE_RWLOCK_UNLOCK(&hitcache_lock
);
114 static void cacheex_add_hitcache(struct s_client
*cl
, ECM_REQUEST
*er
)
116 if (!cfg
.max_hitcache_time
) //we don't want check/save hitcache
118 if (!cfg
.cacheex_wait_timetab
.cevnum
)
120 uint32_t cacheex_wait_time
= get_cacheex_wait_time(er
,NULL
);
121 if (!cacheex_wait_time
)
127 memset(&search
, 0, sizeof(HIT_KEY
));
128 search
.caid
= er
->caid
;
129 search
.prid
= er
->prid
;
130 search
.srvid
= er
->srvid
;
132 SAFE_RWLOCK_WRLOCK(&hitcache_lock
);
134 result
= find_hash_table(&ht_hitcache
, &search
, sizeof(HIT_KEY
), &cacheex_compare_hitkey
);
135 if(!result
) { //not found, add it!
136 if(cs_malloc(&result
, sizeof(CACHE_HIT
)))
138 memset(result
, 0, sizeof(CACHE_HIT
));
139 result
->key
.caid
= er
->caid
;
140 result
->key
.prid
= er
->prid
;
141 result
->key
.srvid
= er
->srvid
;
142 cs_ftime(&result
->max_hitcache_time
);
143 add_hash_table(&ht_hitcache
, &result
->ht_node
, &ll_hitcache
, &result
->ll_node
, result
, &result
->key
, sizeof(HIT_KEY
));
150 result
->grp
|= cl
->grp
;
151 result
->grp_last_max_hitcache_time
|= cl
->grp
;
153 cs_ftime(&result
->time
); //always update time;
156 SAFE_RWLOCK_UNLOCK(&hitcache_lock
);
159 static void cacheex_del_hitcache(struct s_client
*cl
, ECM_REQUEST
*er
)
164 memset(&search
, 0, sizeof(HIT_KEY
));
165 search
.caid
= er
->caid
;
166 search
.prid
= er
->prid
;
167 search
.srvid
= er
->srvid
;
171 result
= find_hash_table(&ht_hitcache
, &search
, sizeof(HIT_KEY
), &cacheex_compare_hitkey
);
174 result
->grp
&= ~cl
->grp
;
175 result
->grp_last_max_hitcache_time
&= ~cl
->grp
;
176 result
= find_hash_table(&ht_hitcache
, &search
, sizeof(HIT_KEY
), &cacheex_compare_hitkey
);
180 SAFE_RWLOCK_WRLOCK(&hitcache_lock
);
181 search_remove_elem_hash_table(&ht_hitcache
, &search
, sizeof(HIT_KEY
), &cacheex_compare_hitkey
);
182 SAFE_RWLOCK_UNLOCK(&hitcache_lock
);
185 void cacheex_cleanup_hitcache(bool force
)
190 int64_t gone
, gone_max_hitcache_time
;
191 int32_t timeout
= (cfg
.max_hitcache_time
+ (cfg
.max_hitcache_time
/ 2))*1000; //1,5
192 int32_t clean_grp
= (cfg
.max_hitcache_time
* 1000);
193 SAFE_RWLOCK_WRLOCK(&hitcache_lock
);
194 i
= get_first_node_list(&ll_hitcache
);
198 cachehit
= get_data_from_node(i
);
207 gone
= comp_timeb(&now
, &cachehit
->time
);
208 gone_max_hitcache_time
= comp_timeb(&now
, &cachehit
->max_hitcache_time
);
210 if(force
|| gone
>timeout
)
212 remove_elem_list(&ll_hitcache
, &cachehit
->ll_node
);
213 remove_elem_hash_table(&ht_hitcache
, &cachehit
->ht_node
);
216 else if(gone_max_hitcache_time
>= clean_grp
){
217 cachehit
->grp
= cachehit
->grp_last_max_hitcache_time
;
218 cachehit
->grp_last_max_hitcache_time
= 0;
219 cs_ftime(&cachehit
->max_hitcache_time
);
223 SAFE_RWLOCK_UNLOCK(&hitcache_lock
);
226 static int32_t cacheex_ecm_hash_calc(uchar
*buf
, int32_t n
)
229 for(i
= 0; i
< n
; i
++)
236 void cacheex_update_hash(ECM_REQUEST
*er
)
238 er
->csp_hash
= cacheex_ecm_hash_calc(er
->ecm
+ 3, er
->ecmlen
- 3);
241 void cacheex_free_csp_lastnodes(ECM_REQUEST
*er
)
243 ll_destroy_free_data(&er
->csp_lastnodes
);
246 void cacheex_set_csp_lastnode(ECM_REQUEST
*er
)
248 er
->csp_lastnodes
= NULL
;
251 void cacheex_set_cacheex_src(ECM_REQUEST
*ecm
, struct s_client
*cl
)
253 if(ecm
->cacheex_src
== cl
)
254 ecm
->cacheex_src
= NULL
;
257 void cacheex_init_cacheex_src(ECM_REQUEST
*ecm
, ECM_REQUEST
*er
)
259 if(!ecm
->cacheex_src
)
260 ecm
->cacheex_src
= er
->cacheex_src
;
263 static void *chkcache_process(void)
265 set_thread_name(__func__
);
268 struct ecm_request_t
*er
, *ecm
;
269 uint8_t add_hitcache_er
;
270 struct s_reader
*cl_rdr
;
271 struct s_reader
*rdr
;
272 struct s_ecm_answer
*ea
;
273 struct s_client
*cex_src
=NULL
;
274 struct s_write_from_cache
*wfc
=NULL
;
276 while(cacheex_running
)
278 cs_readlock(__func__
, &ecmcache_lock
);
279 for(er
= ecmcwcache
; er
; er
= er
->next
)
281 timeout
= time(NULL
)-((cfg
.ctimeout
+500)/1000+1);
282 if(er
->tps
.time
< timeout
)
285 if(er
->rc
<E_UNHANDLED
|| er
->readers_timeout_check
) //already answered
288 //******** CHECK IF FOUND ECM IN CACHE
289 ecm
= check_cache(er
, er
->client
);
290 if(ecm
) //found in cache
292 //check for add_hitcache
293 if(ecm
->cacheex_src
) //cw from cacheex
295 if((er
->cacheex_wait_time
&& !er
->cacheex_wait_time_expired
) || !er
->cacheex_wait_time
) //only when no wait_time expires (or not wait_time)
298 //add_hitcache already called, but we check if we have to call it for these (er) caid|prid|srvid
299 if(ecm
->prid
!=er
->prid
|| ecm
->srvid
!=er
->srvid
)
301 cex_src
= ecm
->cacheex_src
&& is_valid_client(ecm
->cacheex_src
) && !ecm
->cacheex_src
->kill
? ecm
->cacheex_src
: NULL
; //here we should be sure cex client has not been freed!
302 if(cex_src
){ //add_hitcache only if client is really active
304 cl_rdr
= cex_src
->reader
;
305 if(cl_rdr
&& cl_rdr
->cacheex
.mode
== 2)
307 for(ea
= er
->matching_rdr
; ea
; ea
= ea
->next
)
310 if(cl_rdr
== rdr
&& ((ea
->status
& REQUEST_ANSWERED
) == REQUEST_ANSWERED
))
312 cs_log_dbg(D_CACHEEX
|D_CSP
|D_LB
,"{client %s, caid %04X, prid %06X, srvid %04X} [CACHEEX] skip ADD self request!", (check_client(er
->client
)?er
->client
->account
->usr
:"-"),er
->caid
, er
->prid
, er
->srvid
);
313 add_hitcache_er
=0; //don't add hit cache, reader requested self
319 { cacheex_add_hitcache(cex_src
, er
); } //USE cacheex client (to get correct group) and ecm from requesting client (to get correct caid|prid|srvid)!!!
326 //add_hitcache already called, but we have to remove it because cacheex not coming before wait_time
327 if(ecm
->prid
==er
->prid
&& ecm
->srvid
==er
->srvid
)
328 { cacheex_del_hitcache(er
->client
, ecm
); }
331 //END check for add_hitcache
333 if(check_client(er
->client
))
336 if(!cs_malloc(&wfc
, sizeof(struct s_write_from_cache
)))
345 if(!add_job(er
->client
, ACTION_ECM_ANSWER_CACHE
, wfc
, sizeof(struct s_write_from_cache
))) //write_ecm_answer_fromcache
355 cs_readunlock(__func__
, &ecmcache_lock
);
363 void checkcache_process_thread_start(void)
365 start_thread("chkcache_process", (void *) &chkcache_process
, NULL
, NULL
, 1, 1);
368 void cacheex_init(void)
370 // Init random node id
371 get_random_bytes(cacheex_peer_id
, 8);
373 memcpy(cacheex_peer_id
, cc_node_id
, 8);
375 #ifdef MODULE_CAMD35_TCP
376 memcpy(camd35_node_id
, cacheex_peer_id
, 8);
380 void cacheex_clear_account_stats(struct s_auth
*account
)
382 account
->cwcacheexgot
= 0;
383 account
->cwcacheexpush
= 0;
384 account
->cwcacheexhit
= 0;
387 void cacheex_clear_client_stats(struct s_client
*client
)
389 client
->cwcacheexgot
= 0;
390 client
->cwcacheexpush
= 0;
391 client
->cwcacheexhit
= 0;
394 int32_t cacheex_add_stats(struct s_client
*cl
, uint16_t caid
, uint16_t srvid
, uint32_t prid
, uint8_t direction
)
396 if(!cfg
.cacheex_enable_stats
)
399 // create list if doesn't exist
400 if(!cl
->ll_cacheex_stats
)
401 { cl
->ll_cacheex_stats
= ll_create("ll_cacheex_stats"); }
403 time_t now
= time((time_t *)0);
404 LL_ITER itr
= ll_iter_create(cl
->ll_cacheex_stats
);
405 S_CACHEEX_STAT_ENTRY
*cacheex_stats_entry
;
407 // check for existing entry
408 while((cacheex_stats_entry
= ll_iter_next(&itr
)))
410 if(cacheex_stats_entry
->cache_srvid
== srvid
&&
411 cacheex_stats_entry
->cache_caid
== caid
&&
412 cacheex_stats_entry
->cache_prid
== prid
&&
413 cacheex_stats_entry
->cache_direction
== direction
)
415 // we already have this entry - just add count and time
416 cacheex_stats_entry
->cache_count
++;
417 cacheex_stats_entry
->cache_last
= now
;
418 return cacheex_stats_entry
->cache_count
;
422 // if we land here we have to add a new entry
423 if(cs_malloc(&cacheex_stats_entry
, sizeof(S_CACHEEX_STAT_ENTRY
)))
425 cacheex_stats_entry
->cache_caid
= caid
;
426 cacheex_stats_entry
->cache_srvid
= srvid
;
427 cacheex_stats_entry
->cache_prid
= prid
;
428 cacheex_stats_entry
->cache_count
= 1;
429 cacheex_stats_entry
->cache_last
= now
;
430 cacheex_stats_entry
->cache_direction
= direction
;
431 ll_iter_insert(&itr
, cacheex_stats_entry
);
438 int8_t cacheex_maxhop(struct s_client
*cl
)
441 if(cl
->reader
&& cl
->reader
->cacheex
.maxhop
)
442 { maxhop
= cl
->reader
->cacheex
.maxhop
; }
443 else if(cl
->account
&& cl
->account
->cacheex
.maxhop
)
444 { maxhop
= cl
->account
->cacheex
.maxhop
; }
448 static void cacheex_cache_push_to_client(struct s_client
*cl
, ECM_REQUEST
*er
)
450 add_job(cl
, ACTION_CACHE_PUSH_OUT
, er
, 0);
454 * Check for NULL ecmd5
456 static uint8_t checkECMD5(ECM_REQUEST
*er
)
459 for(i
= 0; i
< CS_ECMSTORESIZE
; i
++)
460 if(er
->ecmd5
[i
]) { return 1; }
467 * cacheex=1 CACHE PULL:
468 * Situation: oscam A reader1 has cacheex=1, oscam B account1 has cacheex=1
469 * oscam A gets a ECM request, reader1 send this request to oscam B, oscam B checks his cache
470 * a. not found in cache: return NOK
471 * a. found in cache: return OK+CW
472 * b. not found in cache, but found pending request: wait max cacheexwaittime and check again
473 * oscam B never requests new ECMs
477 * cacheex=2 CACHE PUSH:
478 * Situation: oscam A reader1 has cacheex=2, oscam B account1 has cacheex=2
479 * if oscam B gets a CW, its pushed to oscam A
480 * reader has normal functionality and can request ECMs
482 * Problem: oscam B can only push if oscam A is connected
483 * Problem or feature?: oscam A reader can request ecms from oscam B
488 void cacheex_cache_push(ECM_REQUEST
*er
)
490 if(er
->rc
>= E_NOTFOUND
) { return; }
492 //cacheex=2 mode: push (server->remote)
494 cs_readlock(__func__
, &clientlist_lock
);
495 for(cl
= first_client
->next
; cl
; cl
= cl
->next
)
497 if(check_client(cl
) && er
->cacheex_src
!= cl
)
499 if(get_module(cl
)->num
== R_CSP
) // always send to csp cl
501 if(!er
->cacheex_src
|| cfg
.csp
.allow_reforward
) { cacheex_cache_push_to_client(cl
, er
); } // but not if the origin was cacheex (might loop)
503 else if(cl
->typ
== 'c' && !cl
->dup
&& cl
->account
&& cl
->account
->cacheex
.mode
== 2) //send cache over user
505 if(get_module(cl
)->c_cache_push
// cache-push able
506 && (!er
->grp
|| (cl
->grp
& er
->grp
)) //Group-check
507 /**** OUTGOING FILTER CHECK ***/
508 && (!er
->selected_reader
|| !cacheex_reader(er
->selected_reader
) || !cfg
.block_same_name
|| strcmp(username(cl
), er
->selected_reader
->label
)) //check reader mode-1 loopback by same name
509 && (!er
->selected_reader
|| !cacheex_reader(er
->selected_reader
) || !cfg
.block_same_ip
|| (check_client(er
->selected_reader
->client
) && !IP_EQUAL(cl
->ip
, er
->selected_reader
->client
->ip
))) //check reader mode-1 loopback by same ip
510 && (!cl
->account
->cacheex
.drop_csp
|| checkECMD5(er
)) //cacheex_drop_csp-check
511 && chk_ctab(er
->caid
, &cl
->ctab
) //Caid-check
512 && (!checkECMD5(er
) || chk_ident_filter(er
->caid
, er
->prid
, &cl
->ftab
)) //Ident-check (not for csp: prid=0 always!)
513 && chk_srvid(cl
, er
) //Service-check
514 && chk_csp_ctab(er
, &cl
->account
->cacheex
.filter_caidtab
) //cacheex_ecm_filter
517 cacheex_cache_push_to_client(cl
, er
);
522 cs_readunlock(__func__
, &clientlist_lock
);
525 //cacheex=3 mode: reverse push (reader->server)
526 cs_readlock(__func__
, &readerlist_lock
);
527 cs_readlock(__func__
, &clientlist_lock
);
528 struct s_reader
*rdr
;
529 for(rdr
= first_active_reader
; rdr
; rdr
= rdr
->next
)
532 if(check_client(cl
) && er
->cacheex_src
!= cl
&& rdr
->cacheex
.mode
== 3) //send cache over reader
534 if(rdr
->ph
.c_cache_push
// cache-push able
535 && (!er
->grp
|| (rdr
->grp
& er
->grp
)) //Group-check
536 /**** OUTGOING FILTER CHECK ***/
537 && (!er
->selected_reader
|| !cacheex_reader(er
->selected_reader
) || !cfg
.block_same_name
|| strcmp(username(cl
), er
->selected_reader
->label
)) //check reader mode-1 loopback by same name
538 && (!er
->selected_reader
|| !cacheex_reader(er
->selected_reader
) || !cfg
.block_same_ip
|| (check_client(er
->selected_reader
->client
) && !IP_EQUAL(cl
->ip
, er
->selected_reader
->client
->ip
))) //check reader mode-1 loopback by same ip
539 && (!rdr
->cacheex
.drop_csp
|| checkECMD5(er
)) //cacheex_drop_csp-check
540 && chk_ctab(er
->caid
, &rdr
->ctab
) //Caid-check
541 && (!checkECMD5(er
) || chk_ident_filter(er
->caid
, er
->prid
, &rdr
->ftab
)) //Ident-check (not for csp: prid=0 always!)
542 && chk_srvid(cl
, er
) //Service-check
543 && chk_csp_ctab(er
, &rdr
->cacheex
.filter_caidtab
) //cacheex_ecm_filter
546 cacheex_cache_push_to_client(cl
, er
);
550 cs_readunlock(__func__
, &clientlist_lock
);
551 cs_readunlock(__func__
, &readerlist_lock
);
555 /**** INCOMING FILTER CHECK ***/
556 uint8_t check_cacheex_filter(struct s_client
*cl
, ECM_REQUEST
*er
)
559 if(check_client(cl
) && cl
->typ
== 'p' && cl
->reader
&& cl
->reader
->cacheex
.mode
==2
560 && (!cl
->reader
->cacheex
.drop_csp
|| checkECMD5(er
)) //cacheex_drop_csp-check
561 && chk_ctab(er
->caid
, &cl
->reader
->ctab
) //Caid-check
562 && (!checkECMD5(er
) || chk_ident_filter(er
->caid
, er
->prid
, &cl
->reader
->ftab
)) //Ident-check (not for csp: prid=0 always!)
563 && chk_srvid(cl
, er
) //Service-check
567 if(check_client(cl
) && cl
->typ
== 'c' && cl
->account
&& cl
->account
->cacheex
.mode
==3
568 && (!cl
->account
->cacheex
.drop_csp
|| checkECMD5(er
)) //cacheex_drop_csp-check
569 && chk_ctab(er
->caid
, &cl
->ctab
) //Caid-check
570 && (!checkECMD5(er
) || chk_ident_filter(er
->caid
, er
->prid
, &cl
->ftab
)) //Ident-check (not for csp: prid=0 always!)
571 && chk_srvid(cl
, er
) //Service-check
581 static struct s_cacheex_matcher
*is_cacheex_matcher_matching(ECM_REQUEST
*from_er
, ECM_REQUEST
*to_er
)
583 struct s_cacheex_matcher
*entry
= cfg
.cacheex_matcher
;
584 int8_t v_ok
= (from_er
&& to_er
) ? 2 : 1;
589 && (!entry
->caid
|| entry
->caid
== from_er
->caid
)
590 && (!entry
->provid
|| entry
->provid
== from_er
->prid
)
591 && (!entry
->srvid
|| entry
->srvid
== from_er
->srvid
)
592 && (!entry
->chid
|| entry
->chid
== from_er
->chid
)
593 && (!entry
->pid
|| entry
->pid
== from_er
->pid
)
594 && (!entry
->ecmlen
|| entry
->ecmlen
== from_er
->ecmlen
))
598 && (!entry
->to_caid
|| entry
->to_caid
== to_er
->caid
)
599 && (!entry
->to_provid
|| entry
->to_provid
== to_er
->prid
)
600 && (!entry
->to_srvid
|| entry
->to_srvid
== to_er
->srvid
)
601 && (!entry
->to_chid
|| entry
->to_chid
== to_er
->chid
)
602 && (!entry
->to_pid
|| entry
->to_pid
== to_er
->pid
)
603 && (!entry
->to_ecmlen
|| entry
->to_ecmlen
== to_er
->ecmlen
))
608 if(!from_er
|| !to_er
|| from_er
->srvid
== to_er
->srvid
)
616 bool cacheex_is_match_alias(struct s_client
*cl
, ECM_REQUEST
*er
)
618 return check_client(cl
) && cl
->account
&& cl
->account
->cacheex
.mode
== 1 && is_cacheex_matcher_matching(NULL
, er
);
621 static void log_cacheex_cw(ECM_REQUEST
*er
, char *reason
)
624 uint8_t remotenodeid
[8];
625 data
= ll_last_element(er
->csp_lastnodes
);
627 { memcpy(remotenodeid
, data
, 8); }
629 { memset(remotenodeid
, 0 , 8); }
632 format_ecm(er
, buf_ecm
, 109);
633 cs_log_dbg(D_CACHEEX
,"got pushed ecm [%s]: %s - odd/even 0x%x - CSP cw: %s - pushed from %s, at hop %d, origin node-id %" PRIu64
"X",
634 reason
, buf_ecm
, er
->ecm
[0], (checkECMD5(er
)?"NO":"YES"), er
->from_csp
? "csp" : username((er
->cacheex_src
?er
->cacheex_src
:er
->client
)), ll_count(er
->csp_lastnodes
), er
->csp_lastnodes
? cacheex_node_id(remotenodeid
): 0);
637 static int32_t cacheex_add_to_cache_int(struct s_client
*cl
, ECM_REQUEST
*er
, int8_t csp
)
639 if(er
->rc
>= E_NOTFOUND
) { return 0; }
643 if(!csp
&& cl
->reader
&& cl
->reader
->cacheex
.mode
!= 2) //from reader
645 cs_log_dbg(D_CACHEEX
, "CACHEX received, but disabled for %s", username(cl
));
648 if(!csp
&& !cl
->reader
&& cl
->account
&& cl
->account
->cacheex
.mode
!= 3) //from user
650 cs_log_dbg(D_CACHEEX
, "CACHEX received, but disabled for %s", username(cl
));
653 if(!csp
&& !cl
->reader
&& !cl
->account
) //not active!
655 cs_log_dbg(D_CACHEEX
, "CACHEX received, but invalid client state %s", username(cl
));
659 uint8_t selectedForIgnChecksum
= chk_if_ignore_checksum(er
, cfg
.disablecrccws
, &cfg
.disablecrccws_only_for
);
660 if (cl
->typ
== 'c') {
661 selectedForIgnChecksum
+= chk_if_ignore_checksum (er
, cl
->account
->disablecrccacheex
, &cl
->account
->disablecrccacheex_only_for
);
663 if (cl
->typ
== 'p') {
664 selectedForIgnChecksum
+= chk_if_ignore_checksum (er
, cl
->reader
->disablecrccws
, &cl
->reader
->disablecrccws_only_for
);
668 if(cfg
.disablecrccws
== 0 || (cl
->typ
== 'c' && cl
->account
->disablecrccacheex
== 0) || ( cl
->typ
== 'p' && cl
->reader
->disablecrccws
== 0))
670 for(i
= 0; i
< 16; i
+= 4)
672 c
= ((er
->cw
[i
] + er
->cw
[i
+ 1] + er
->cw
[i
+ 2]) & 0xff);
674 if((i
!=12) && selectedForIgnChecksum
&& (er
->cw
[i
+ 3] != c
)){
678 if(er
->cw
[i
+ 3] != c
)
680 cs_log_dump_dbg(D_CACHEEX
, er
->cw
, 16, "push received cw with chksum error from %s", csp
? "csp" : username(cl
));
683 { cl
->account
->cwcacheexerr
++; }
689 if(chk_is_null_CW(er
->cw
) && er
->caid
!=0x2600) // 0x2600 used by biss and constant cw could be indeed zero
691 cs_log_dump_dbg(D_CACHEEX
, er
->cw
, 16, "push received null cw from %s", csp
? "csp" : username(cl
));
694 { cl
->account
->cwcacheexerr
++; }
698 if(get_odd_even(er
)==0){
699 cs_log_dbg(D_CACHEEX
, "push received ecm with null odd/even byte from %s", csp
? "csp" : username(cl
));
702 { cl
->account
->cwcacheexerr
++; }
706 if(!chk_halfCW(er
, er
->cw
)){
707 log_cacheex_cw(er
, "bad half cw");
711 { cl
->account
->cwcacheexerr
++; }
715 if((csp
&& cfg
.csp
.block_fakecws
) || (cl
->reader
&& cl
->reader
->cacheex
.block_fakecws
)
716 || (!cl
->reader
&& cl
->account
&& cl
->account
->cacheex
.block_fakecws
))
718 if(chk_is_fakecw(er
->cw
))
720 cs_log_dbg(D_CACHEEX
, "push received fake cw from %s", csp
? "csp" : username(cl
));
723 { cl
->account
->cwcacheexerr
++; }
728 er
->grp
|= cl
->grp
; //ok for mode2 reader too: cl->reader->grp
730 er
->cacheex_src
= cl
;
731 er
->selected_reader
= cl
->reader
;
732 er
->client
= NULL
; //No Owner! So no fallback!
738 { cl
->account
->cwcacheexgot
++; }
739 first_client
->cwcacheexgot
++;
742 cacheex_add_hitcache(cl
, er
); //we have to call it before add_cache, because in chk_process we could remove it!
744 cacheex_add_stats(cl
, er
->caid
, er
->srvid
, er
->prid
, 1);
746 cs_writelock(__func__
, &ecm_pushed_deleted_lock
);
747 er
->next
= ecm_pushed_deleted
;
748 ecm_pushed_deleted
= er
;
749 cs_writeunlock(__func__
, &ecm_pushed_deleted_lock
);
751 return 1; //NO free, we have to wait cache push out stuff ends.
755 void cacheex_add_to_cache(struct s_client
*cl
, ECM_REQUEST
*er
)
757 er
->from_cacheex
= 1;
758 if(!cacheex_add_to_cache_int(cl
, er
, 0))
759 { free_push_in_ecm(er
); }
762 void cacheex_add_to_cache_from_csp(struct s_client
*cl
, ECM_REQUEST
*er
)
764 if(!cacheex_add_to_cache_int(cl
, er
, 1))
765 { free_push_in_ecm(er
); }
770 //caid:prov:srvid:pid:chid:ecmlen=caid:prov:srvid:pid:chid:ecmlen[,validfrom,validto]
771 //validfrom: default=-2000
772 //validto: default=4000
773 //valid time if found in cache
774 static struct s_cacheex_matcher
*cacheex_matcher_read_int(void)
776 FILE *fp
= open_config_file(cs_cacheex_matcher
);
782 int32_t i
, ret
, count
= 0;
783 struct s_cacheex_matcher
*new_cacheex_matcher
= NULL
, *entry
, *last
= NULL
;
786 while(fgets(token
, sizeof(token
), fp
))
789 if(strlen(token
) <= 1) { continue; }
790 if(token
[0] == '#' || token
[0] == '/') { continue; }
791 if(strlen(token
) > 100) { continue; }
793 for(i
= 0; i
< (int)strlen(token
); i
++)
795 if((token
[i
] == ':' || token
[i
] == ' ') && token
[i
+ 1] == ':')
797 memmove(token
+ i
+ 2, token
+ i
+ 1, strlen(token
) - i
+ 1);
800 if(token
[i
] == '#' || token
[i
] == '/')
808 uint32_t caid
= 0, provid
= 0, srvid
= 0, pid
= 0, chid
= 0, ecmlen
= 0;
809 uint32_t to_caid
= 0, to_provid
= 0, to_srvid
= 0, to_pid
= 0, to_chid
= 0, to_ecmlen
= 0;
810 int32_t valid_from
= -2000, valid_to
= 4000;
812 ret
= sscanf(token
, "%c:%4x:%6x:%4x:%4x:%4x:%4X=%4x:%6x:%4x:%4x:%4x:%4X,%4d,%4d",
814 &caid
, &provid
, &srvid
, &pid
, &chid
, &ecmlen
,
815 &to_caid
, &to_provid
, &to_srvid
, &to_pid
, &to_chid
, &to_ecmlen
,
816 &valid_from
, &valid_to
);
818 type
= tolower(type
);
820 if(ret
< 7 || type
!= 'm')
823 if(!cs_malloc(&entry
, sizeof(struct s_cacheex_matcher
)))
826 return new_cacheex_matcher
;
832 entry
->provid
= provid
;
833 entry
->srvid
= srvid
;
836 entry
->ecmlen
= ecmlen
;
837 entry
->to_caid
= to_caid
;
838 entry
->to_provid
= to_provid
;
839 entry
->to_srvid
= to_srvid
;
840 entry
->to_pid
= to_pid
;
841 entry
->to_chid
= to_chid
;
842 entry
->to_ecmlen
= to_ecmlen
;
843 entry
->valid_from
= valid_from
;
844 entry
->valid_to
= valid_to
;
846 cs_log_dbg(D_TRACE
, "cacheex-matcher: %c: %04X@%06X:%04X:%04X:%04X:%02X = %04X@%06X:%04X:%04X:%04X:%02X valid %d/%d",
847 entry
->type
, entry
->caid
, entry
->provid
, entry
->srvid
, entry
->pid
, entry
->chid
, entry
->ecmlen
,
848 entry
->to_caid
, entry
->to_provid
, entry
->to_srvid
, entry
->to_pid
, entry
->to_chid
, entry
->to_ecmlen
,
849 entry
->valid_from
, entry
->valid_to
);
851 if(!new_cacheex_matcher
)
853 new_cacheex_matcher
= entry
;
854 last
= new_cacheex_matcher
;
864 { cs_log("%d entries read from %s", count
, cs_cacheex_matcher
); }
868 return new_cacheex_matcher
;
871 void cacheex_load_config_file(void)
873 struct s_cacheex_matcher
*entry
, *old_list
;
875 old_list
= cfg
.cacheex_matcher
;
876 cfg
.cacheex_matcher
= cacheex_matcher_read_int();
880 entry
= old_list
->next
;
888 CWCHECK
get_cwcheck(ECM_REQUEST
*er
){
893 for(i
= 0; i
< cfg
.cacheex_cwcheck_tab
.cwchecknum
; i
++)
895 CWCHECKTAB_DATA
*d
= &cfg
.cacheex_cwcheck_tab
.cwcheckdata
[i
];
897 if(i
== 0 && d
->caid
<= 0)
900 counter
= d
->counter
;
901 continue; //check other, only valid for unset
904 if(d
->caid
== er
->caid
|| d
->caid
== er
->caid
>> 8 || ((d
->cmask
>= 0 && (er
->caid
& d
->cmask
) == d
->caid
) || d
->caid
== -1))
906 if((d
->prid
>= 0 && d
->prid
== (int32_t)er
->prid
) || d
->prid
== -1)
908 if((d
->srvid
>= 0 && d
->srvid
== er
->srvid
) || d
->srvid
== -1)
911 counter
= d
->counter
;
919 //check for correct values
920 if(mode
>2 || mode
<0) mode
=0;
921 if(counter
<1) counter
=1;
924 memset(&check_cw
, 0, sizeof(CWCHECK
));
925 check_cw
.mode
= mode
;
926 check_cw
.counter
= counter
;
933 uint16_t get_cacheex_mode1_delay(ECM_REQUEST
*er
)
935 return caidvaluetab_get_value(&cfg
.cacheex_mode1_delay_tab
, er
->caid
, 0);
940 uint32_t get_cacheex_wait_time(ECM_REQUEST
*er
, struct s_client
*cl
)
942 int32_t i
, dwtime
= -1, awtime
= -1;
944 for(i
= 0; i
< cfg
.cacheex_wait_timetab
.cevnum
; i
++)
946 CECSPVALUETAB_DATA
*d
= &cfg
.cacheex_wait_timetab
.cevdata
[i
];
948 if(i
== 0 && d
->caid
<= 0)
952 continue; //check other, only valid for unset
955 if(d
->caid
== er
->caid
|| d
->caid
== er
->caid
>> 8 || ((d
->cmask
>= 0 && (er
->caid
& d
->cmask
) == d
->caid
) || d
->caid
== -1))
957 if((d
->prid
>= 0 && d
->prid
== (int32_t)er
->prid
) || d
->prid
== -1)
959 if((d
->srvid
>= 0 && d
->srvid
== er
->srvid
) || d
->srvid
== -1)
970 if(awtime
> 0 && (dwtime
<= 0 || awtime
==dwtime
) ) //if awtime==dwtime useless check hitcache
980 if(awtime
> 0 || dwtime
> 0)
982 //if found last in cache return dynwaittime else alwayswaittime
983 if(cacheex_check_hitcache(er
,cl
))
984 { return dwtime
>= awtime
? dwtime
: awtime
; }
986 { return awtime
> 0 ? awtime
: 0; }
992 int32_t chk_csp_ctab(ECM_REQUEST
*er
, CECSPVALUETAB
*tab
)
994 if(!er
->caid
|| !tab
->cevnum
)
995 { return 1; } // nothing setup we add all
997 for(i
= 0; i
< tab
->cevnum
; i
++)
999 CECSPVALUETAB_DATA
*d
= &tab
->cevdata
[i
];
1002 if(d
->caid
== er
->caid
|| d
->caid
== er
->caid
>> 8 || ((d
->cmask
>= 0 && (er
->caid
& d
->cmask
) == d
->caid
) || d
->caid
== -1))
1004 if((d
->prid
>= 0 && d
->prid
== (int32_t)er
->prid
) || d
->prid
== -1)
1006 if((d
->srvid
>= 0 && d
->srvid
== er
->srvid
) || d
->srvid
== -1)
1017 void cacheex_push_out(struct s_client
*cl
, ECM_REQUEST
*er
) {
1018 int32_t res
= 0, stats
= -1;
1019 struct s_reader
*reader
= cl
->reader
;
1020 struct s_module
*module
= get_module(cl
);
1021 // cc-nodeid-list-check
1024 if(reader
->ph
.c_cache_push_chk
&& !reader
->ph
.c_cache_push_chk(cl
, er
))
1026 res
= reader
->ph
.c_cache_push(cl
, er
);
1027 stats
= cacheex_add_stats(cl
, er
->caid
, er
->srvid
, er
->prid
, 0);
1031 if(module
->c_cache_push_chk
&& !module
->c_cache_push_chk(cl
, er
))
1033 res
= module
->c_cache_push(cl
, er
);
1035 debug_ecm(D_CACHEEX
, "pushed ECM %s to %s res %d stats %d", buf
, username(cl
), res
, stats
);
1036 cl
->cwcacheexpush
++;
1038 { cl
->account
->cwcacheexpush
++; }
1039 first_client
->cwcacheexpush
++;
1042 bool cacheex_check_queue_length(struct s_client
*cl
)
1044 // Avoid full running queues:
1045 if(ll_count(cl
->joblist
) <= 2000)
1048 cs_log_dbg(D_TRACE
, "WARNING: job queue %s %s has more than 2000 jobs! count=%d, dropped!",
1049 cl
->typ
== 'c' ? "client" : "reader",
1050 username(cl
), ll_count(cl
->joblist
));
1052 SAFE_MUTEX_LOCK(&cl
->thread_lock
);
1053 if(cl
&& !cl
->kill
&& cl
->thread
&& cl
->thread_active
)
1055 // Just test for invalid thread id:
1056 if(pthread_detach(cl
->thread
) == ESRCH
)
1058 cl
->thread_active
= 0;
1059 cs_log_dbg(D_TRACE
, "WARNING: %s %s thread died!",
1060 cl
->typ
== 'c' ? "client" : "reader", username(cl
));
1063 SAFE_MUTEX_UNLOCK(&cl
->thread_lock
);
1067 void cacheex_mode1_delay(ECM_REQUEST
*er
)
1069 if(!er
->cacheex_wait_time_expired
1070 && er
->cacheex_mode1_delay
1071 && er
->cacheex_reader_count
> 0
1073 && er
->rc
>= E_UNHANDLED
)
1075 cs_log_dbg(D_LB
, "{client %s, caid %04X, prid %06X, srvid %04X} cacheex_mode1_delay timeout! ", (check_client(er
->client
) ? er
->client
->account
->usr
: "-"), er
->caid
, er
->prid
, er
->srvid
);
1076 request_cw_from_readers(er
, 1); // setting stop_stage=1, we request only cacheex mode 1 readers. Others are requested at cacheex timeout!
1080 void cacheex_timeout(ECM_REQUEST
*er
)
1082 if(er
->cacheex_wait_time_expired
)
1084 er
->cacheex_wait_time_expired
= 1;
1085 if(er
->rc
>= E_UNHANDLED
)
1087 cs_log_dbg(D_LB
, "{client %s, caid %04X, prid %06X, srvid %04X} cacheex timeout! ", (check_client(er
->client
) ? er
->client
->account
->usr
: "-"), er
->caid
, er
->prid
, er
->srvid
);
1088 //if check_cw mode=0, first try to get cw from cache without check counter!
1089 CWCHECK check_cw
= get_cwcheck(er
);
1092 struct ecm_request_t
*ecm
=NULL
;
1093 ecm
= check_cache(er
, er
->client
);
1094 if(ecm
) //found in cache
1096 struct s_write_from_cache
*wfc
=NULL
;
1097 if(!cs_malloc(&wfc
, sizeof(struct s_write_from_cache
)))
1104 if(!add_job(er
->client
, ACTION_ECM_ANSWER_CACHE
, wfc
, sizeof(struct s_write_from_cache
))) //write_ecm_answer_fromcache
1109 //check if "normal" readers selected, if not send NOT FOUND!
1110 //cacheex1-client (having always no "normal" reader), or not-cacheex-1 client with no normal readers available (or filtered by LB)
1111 if( (er
->reader_count
+ er
->fallback_reader_count
- er
->cacheex_reader_count
) <= 0 )
1113 if(!cfg
.wait_until_ctimeout
){
1114 er
->rc
= E_NOTFOUND
;
1115 er
->selected_reader
= NULL
;
1117 cs_log_dbg(D_LB
, "{client %s, caid %04X, prid %06X, srvid %04X} cacheex timeout: NO \"normal\" readers... not_found! ", (check_client(er
->client
) ? er
->client
->account
->usr
: "-"), er
->caid
, er
->prid
, er
->srvid
);
1118 send_dcw(er
->client
, er
);
1125 debug_ecm(D_TRACE
, "request for %s %s", username(er
->client
), buf
);
1126 request_cw_from_readers(er
, 0);