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 #include "oscam-array.h"
25 #define cs_cacheex_matcher "oscam.cacheex"
27 extern uint8_t cc_node_id
[8];
28 extern uint8_t camd35_node_id
[8];
30 uint8_t cacheex_peer_id
[8];
32 extern CS_MUTEX_LOCK ecm_pushed_deleted_lock
;
33 extern struct ecm_request_t
*ecm_pushed_deleted
;
34 extern CS_MUTEX_LOCK ecmcache_lock
;
35 extern struct ecm_request_t
*ecmcwcache
;
37 // HIT CACHE functions **************************************************************
39 typedef struct hit_key_t
{
45 typedef struct cache_hit_t
{
48 struct timeb max_hitcache_time
;
50 uint64_t grp_last_max_hitcache_time
;
52 int32_t waittime_block
;
58 static pthread_rwlock_t hitcache_lock
;
59 static hash_table ht_hitcache
;
60 static list ll_hitcache
;
61 static bool cacheex_running
;
63 void cacheex_init_hitcache(void)
65 init_hash_table(&ht_hitcache
, &ll_hitcache
);
66 if (pthread_rwlock_init(&hitcache_lock
,NULL
) != 0)
67 cs_log("Error creating lock hitcache_lock!");
68 cacheex_running
= true;
71 void cacheex_free_hitcache(void)
73 cacheex_running
= false;
74 cacheex_cleanup_hitcache(true);
75 deinitialize_hash_table(&ht_hitcache
);
76 pthread_rwlock_destroy(&hitcache_lock
);
79 static int cacheex_compare_hitkey(const void *arg
, const void *obj
)
81 if(((const HIT_KEY
*)arg
)->caid
==((const CACHE_HIT
*)obj
)->key
.caid
82 && ((const HIT_KEY
*)arg
)->prid
==((const CACHE_HIT
*)obj
)->key
.prid
83 && ((const HIT_KEY
*)arg
)->srvid
==((const CACHE_HIT
*)obj
)->key
.srvid
)
90 static int32_t cacheex_check_hitcache(ECM_REQUEST
*er
, struct s_client
*cl
)
94 memset(&search
, 0, sizeof(HIT_KEY
));
95 search
.caid
= er
->caid
;
96 search
.prid
= er
->prid
;
97 search
.srvid
= er
->srvid
;
98 SAFE_RWLOCK_RDLOCK(&hitcache_lock
);
99 result
= find_hash_table(&ht_hitcache
, &search
, sizeof(HIT_KEY
), &cacheex_compare_hitkey
);
103 int64_t gone
= comp_timeb(&now
, &result
->time
);
104 uint64_t grp
= cl
?cl
->grp
:0;
107 gone
<= (cfg
.max_hitcache_time
*1000)
109 (!grp
|| !result
->grp
|| (grp
& result
->grp
))
110 #ifdef CS_CACHEEX_AIO
112 result
->waittime_block
<= cfg
.waittime_block_start
116 SAFE_RWLOCK_UNLOCK(&hitcache_lock
);
120 SAFE_RWLOCK_UNLOCK(&hitcache_lock
);
124 static void cacheex_add_hitcache(struct s_client
*cl
, ECM_REQUEST
*er
)
126 if (!cfg
.max_hitcache_time
) // we don't want check/save hitcache
128 if (!cfg
.cacheex_wait_timetab
.cevnum
)
130 uint32_t cacheex_wait_time
= get_cacheex_wait_time(er
,NULL
);
131 if (!cacheex_wait_time
)
137 memset(&search
, 0, sizeof(HIT_KEY
));
138 search
.caid
= er
->caid
;
139 search
.prid
= er
->prid
;
140 search
.srvid
= er
->srvid
;
142 SAFE_RWLOCK_WRLOCK(&hitcache_lock
);
144 result
= find_hash_table(&ht_hitcache
, &search
, sizeof(HIT_KEY
), &cacheex_compare_hitkey
);
145 if(!result
) // not found, add it!
147 if(cs_malloc(&result
, sizeof(CACHE_HIT
)))
149 memset(result
, 0, sizeof(CACHE_HIT
));
150 result
->key
.caid
= er
->caid
;
151 result
->key
.prid
= er
->prid
;
152 result
->key
.srvid
= er
->srvid
;
153 cs_ftime(&result
->max_hitcache_time
);
154 #ifdef CS_CACHEEX_AIO
155 result
->waittime_block
= 0;
157 add_hash_table(&ht_hitcache
, &result
->ht_node
, &ll_hitcache
, &result
->ll_node
, result
, &result
->key
, sizeof(HIT_KEY
));
165 result
->grp
|= cl
->grp
;
166 result
->grp_last_max_hitcache_time
|= cl
->grp
;
168 cs_ftime(&result
->time
); //always update time;
171 SAFE_RWLOCK_UNLOCK(&hitcache_lock
);
174 static void cacheex_del_hitcache(struct s_client
*cl
, ECM_REQUEST
*er
)
179 memset(&search
, 0, sizeof(HIT_KEY
));
180 search
.caid
= er
->caid
;
181 search
.prid
= er
->prid
;
182 search
.srvid
= er
->srvid
;
186 result
= find_hash_table(&ht_hitcache
, &search
, sizeof(HIT_KEY
), &cacheex_compare_hitkey
);
189 result
->grp
&= ~cl
->grp
;
190 result
->grp_last_max_hitcache_time
&= ~cl
->grp
;
191 result
= find_hash_table(&ht_hitcache
, &search
, sizeof(HIT_KEY
), &cacheex_compare_hitkey
);
195 SAFE_RWLOCK_WRLOCK(&hitcache_lock
);
196 search_remove_elem_hash_table(&ht_hitcache
, &search
, sizeof(HIT_KEY
), &cacheex_compare_hitkey
);
197 SAFE_RWLOCK_UNLOCK(&hitcache_lock
);
200 void cacheex_cleanup_hitcache(bool force
)
205 int64_t gone
, gone_max_hitcache_time
;
206 int32_t timeout
= (cfg
.max_hitcache_time
+ (cfg
.max_hitcache_time
/ 2)) * 1000; // 1,5
207 int32_t clean_grp
= (cfg
.max_hitcache_time
* 1000);
209 SAFE_RWLOCK_WRLOCK(&hitcache_lock
);
210 i
= get_first_node_list(&ll_hitcache
);
214 cachehit
= get_data_from_node(i
);
223 gone
= comp_timeb(&now
, &cachehit
->time
);
224 gone_max_hitcache_time
= comp_timeb(&now
, &cachehit
->max_hitcache_time
);
226 if(force
|| gone
>timeout
227 #ifdef CS_CACHEEX_AIO
228 || (cachehit
->waittime_block
> (cfg
.waittime_block_time
/ 3 + 1))
232 remove_elem_list(&ll_hitcache
, &cachehit
->ll_node
);
233 remove_elem_hash_table(&ht_hitcache
, &cachehit
->ht_node
);
236 else if(gone_max_hitcache_time
>= clean_grp
){
237 cachehit
->grp
= cachehit
->grp_last_max_hitcache_time
;
238 cachehit
->grp_last_max_hitcache_time
= 0;
239 cs_ftime(&cachehit
->max_hitcache_time
);
242 #ifdef CS_CACHEEX_AIO
243 if(cfg
.waittime_block_start
&& (cachehit
&& cachehit
->waittime_block
>= cfg
.waittime_block_start
))
245 cachehit
->waittime_block
++;
250 SAFE_RWLOCK_UNLOCK(&hitcache_lock
);
253 static int32_t cacheex_ecm_hash_calc(uint8_t *buf
, int32_t n
)
256 for(i
= 0; i
< n
; i
++)
263 void cacheex_update_hash(ECM_REQUEST
*er
)
265 er
->csp_hash
= cacheex_ecm_hash_calc(er
->ecm
+ 3, er
->ecmlen
- 3);
268 void cacheex_free_csp_lastnodes(ECM_REQUEST
*er
)
270 ll_destroy_free_data(&er
->csp_lastnodes
);
273 void cacheex_set_csp_lastnode(ECM_REQUEST
*er
)
275 er
->csp_lastnodes
= NULL
;
278 void cacheex_set_cacheex_src(ECM_REQUEST
*ecm
, struct s_client
*cl
)
280 if(ecm
->cacheex_src
== cl
)
281 ecm
->cacheex_src
= NULL
;
284 void cacheex_init_cacheex_src(ECM_REQUEST
*ecm
, ECM_REQUEST
*er
)
286 if(!ecm
->cacheex_src
)
287 ecm
->cacheex_src
= er
->cacheex_src
;
290 static void *chkcache_process(void)
292 set_thread_name(__func__
);
295 struct ecm_request_t
*er
, *ecm
;
296 uint8_t add_hitcache_er
;
297 struct s_reader
*cl_rdr
;
298 struct s_reader
*rdr
;
299 struct s_ecm_answer
*ea
;
300 struct s_client
*cex_src
= NULL
;
301 struct s_write_from_cache
*wfc
= NULL
;
303 while(cacheex_running
)
305 cs_readlock(__func__
, &ecmcache_lock
);
306 for(er
= ecmcwcache
; er
; er
= er
->next
)
308 timeout
= time(NULL
) - ((cfg
.ctimeout
+ 500) / 1000 + 1);
309 if(er
->tps
.time
< timeout
)
312 if(er
->rc
< E_UNHANDLED
|| er
->readers_timeout_check
) // already answered
315 // CHECK IF FOUND ECM IN CACHE
316 ecm
= check_cache(er
, er
->client
);
317 if(ecm
) // found in cache
319 // check for add_hitcache
320 if(ecm
->cacheex_src
) // cw from cacheex
322 // only when no wait_time expires (or not wait_time)
323 if((er
->cacheex_wait_time
&& !er
->cacheex_wait_time_expired
) || !er
->cacheex_wait_time
)
325 // add_hitcache already called, but we check if we have to call it for these (er) caid|prid|srvid
326 if(ecm
->prid
!=er
->prid
|| ecm
->srvid
!=er
->srvid
)
328 // here we should be sure cex client has not been freed!
329 cex_src
= ecm
->cacheex_src
&& is_valid_client(ecm
->cacheex_src
) && !ecm
->cacheex_src
->kill
? ecm
->cacheex_src
: NULL
;
331 if(cex_src
) // add_hitcache only if client is really active
334 cl_rdr
= cex_src
->reader
;
336 if(cl_rdr
&& cl_rdr
->cacheex
.mode
== 2)
338 for(ea
= er
->matching_rdr
; ea
; ea
= ea
->next
)
341 if(cl_rdr
== rdr
&& ((ea
->status
& REQUEST_ANSWERED
) == REQUEST_ANSWERED
))
343 cs_log_dbg(D_CACHEEX
| D_CSP
| D_LB
,"{client %s, caid %04X, prid %06X, srvid %04X} [CACHEEX] skip ADD self request!",
344 (check_client(er
->client
) ? er
->client
->account
->usr
: "-"), er
->caid
, er
->prid
, er
->srvid
);
346 add_hitcache_er
=0; // don't add hit cache, reader requested self
351 // USE cacheex client (to get correct group) and ecm
352 // from requesting client (to get correct caid|prid|srvid)!!!
355 cacheex_add_hitcache(cex_src
, er
);
363 // add_hitcache already called, but we have to remove it because cacheex not coming before wait_time
364 if(ecm
->prid
== er
->prid
&& ecm
->srvid
== er
->srvid
)
365 { cacheex_del_hitcache(er
->client
, ecm
); }
368 // END check for add_hitcache
370 if(check_client(er
->client
))
373 if(!cs_malloc(&wfc
, sizeof(struct s_write_from_cache
)))
382 if(!add_job(er
->client
, ACTION_ECM_ANSWER_CACHE
, wfc
, sizeof(struct s_write_from_cache
))) // write_ecm_answer_fromcache
394 cs_readunlock(__func__
, &ecmcache_lock
);
401 void checkcache_process_thread_start(void)
403 start_thread("chkcache_process", (void *)&chkcache_process
, NULL
, NULL
, 1, 1);
406 void cacheex_init(void)
408 // Init random node id
409 get_random_bytes(cacheex_peer_id
, 8);
411 memcpy(cacheex_peer_id
, cc_node_id
, 8);
413 #ifdef MODULE_CAMD35_TCP
414 memcpy(camd35_node_id
, cacheex_peer_id
, 8);
418 void cacheex_clear_account_stats(struct s_auth
*account
)
420 account
->cwcacheexgot
= 0;
421 account
->cwcacheexpush
= 0;
422 account
->cwcacheexhit
= 0;
423 #ifdef CS_CACHEEX_AIO
424 account
->cwcacheexgotlg
= 0;
425 account
->cwcacheexpushlg
= 0;
429 void cacheex_clear_client_stats(struct s_client
*client
)
431 client
->cwcacheexgot
= 0;
432 client
->cwcacheexpush
= 0;
433 client
->cwcacheexhit
= 0;
434 #ifdef CS_CACHEEX_AIO
435 client
->cwcacheexgotlg
= 0;
436 client
->cwcacheexpushlg
= 0;
440 int32_t cacheex_add_stats(struct s_client
*cl
, uint16_t caid
, uint16_t srvid
, uint32_t prid
, uint8_t direction
441 #ifdef CS_CACHEEX_AIO
442 , uint8_t localgenerated
446 if(!cfg
.cacheex_enable_stats
)
449 // create list if doesn't exist
450 if(!cl
->ll_cacheex_stats
)
451 { cl
->ll_cacheex_stats
= ll_create("ll_cacheex_stats"); }
453 time_t now
= time((time_t *)0);
454 LL_ITER itr
= ll_iter_create(cl
->ll_cacheex_stats
);
455 S_CACHEEX_STAT_ENTRY
*cacheex_stats_entry
;
457 // check for existing entry
458 while((cacheex_stats_entry
= ll_iter_next(&itr
)))
460 if(cacheex_stats_entry
->cache_srvid
== srvid
&&
461 cacheex_stats_entry
->cache_caid
== caid
&&
462 cacheex_stats_entry
->cache_prid
== prid
&&
463 cacheex_stats_entry
->cache_direction
== direction
)
465 // we already have this entry - just add count and time
466 cacheex_stats_entry
->cache_count
++;
467 #ifdef CS_CACHEEX_AIO
469 cacheex_stats_entry
->cache_count_lg
++;
471 cacheex_stats_entry
->cache_last
= now
;
472 return cacheex_stats_entry
->cache_count
;
476 // if we land here we have to add a new entry
477 if(cs_malloc(&cacheex_stats_entry
, sizeof(S_CACHEEX_STAT_ENTRY
)))
479 cacheex_stats_entry
->cache_caid
= caid
;
480 cacheex_stats_entry
->cache_srvid
= srvid
;
481 cacheex_stats_entry
->cache_prid
= prid
;
482 cacheex_stats_entry
->cache_count
= 1;
483 #ifdef CS_CACHEEX_AIO
485 cacheex_stats_entry
->cache_count_lg
= 1;
487 cacheex_stats_entry
->cache_last
= now
;
488 cacheex_stats_entry
->cache_direction
= direction
;
489 ll_iter_insert(&itr
, cacheex_stats_entry
);
495 int8_t cacheex_maxhop(struct s_client
*cl
)
498 if(cl
->reader
&& cl
->reader
->cacheex
.maxhop
)
499 { maxhop
= cl
->reader
->cacheex
.maxhop
; }
500 else if(cl
->account
&& cl
->account
->cacheex
.maxhop
)
501 { maxhop
= cl
->account
->cacheex
.maxhop
; }
505 #ifdef CS_CACHEEX_AIO
506 int8_t cacheex_maxhop_lg(struct s_client
*cl
)
509 int maxhop
= cacheex_maxhop(cl
);
510 int maxhop_lg
= maxhop
;
512 if(cl
->reader
&& cl
->reader
->cacheex
.maxhop_lg
)
514 if(cl
->reader
->cacheex
.maxhop_lg
> max
)
516 cl
->reader
->cacheex
.maxhop_lg
= max
;
519 if(cl
->reader
->cacheex
.maxhop_lg
< maxhop
)
525 maxhop_lg
= cl
->reader
->cacheex
.maxhop_lg
;
528 cl
->reader
->cacheex
.maxhop_lg
= maxhop_lg
;
530 else if(cl
->account
&& cl
->account
->cacheex
.maxhop_lg
)
532 if(cl
->account
->cacheex
.maxhop_lg
> max
)
534 cl
->account
->cacheex
.maxhop_lg
= max
;
537 if(cl
->account
->cacheex
.maxhop_lg
< maxhop
)
543 maxhop_lg
= cl
->account
->cacheex
.maxhop_lg
;
546 cl
->account
->cacheex
.maxhop_lg
= maxhop_lg
;
552 static void cacheex_cache_push_to_client(struct s_client
*cl
, ECM_REQUEST
*er
)
554 add_job(cl
, ACTION_CACHE_PUSH_OUT
, er
, 0);
558 * Check for NULL ecmd5
560 static uint8_t checkECMD5(ECM_REQUEST
*er
)
563 for(i
= 0; i
< CS_ECMSTORESIZE
; i
++)
564 if(er
->ecmd5
[i
]) { return 1; }
568 #ifdef CS_CACHEEX_AIO
569 static uint8_t chk_cwcheck(ECM_REQUEST
*er
, uint8_t cw_check_for_push
)
571 if(!cw_check_for_push
)
575 check_cw
= get_cwcheck(er
);
577 if(check_cw
.mode
&& check_cw
.counter
> 1)
579 if(er
->cw_count
>= check_cw
.counter
)
585 cs_log_dbg(D_CACHEEX
, "push denied - cacheex_check_cw.counter: %u > er->cw_count: %u", check_cw
.counter
, er
->cw_count
);
599 * cacheex=1 CACHE PULL:
600 * Situation: oscam A reader1 has cacheex=1, oscam B account1 has cacheex=1
601 * oscam A gets a ECM request, reader1 send this request to oscam B, oscam B checks his cache
602 * a. not found in cache: return NOK
603 * a. found in cache: return OK+CW
604 * b. not found in cache, but found pending request: wait max cacheexwaittime and check again
605 * oscam B never requests new ECMs
609 * cacheex=2 CACHE PUSH:
610 * Situation: oscam A reader1 has cacheex=2, oscam B account1 has cacheex=2
611 * if oscam B gets a CW, its pushed to oscam A
612 * reader has normal functionality and can request ECMs
614 * Problem: oscam B can only push if oscam A is connected
615 * Problem or feature?: oscam A reader can request ecms from oscam B
620 void cacheex_cache_push(ECM_REQUEST
*er
)
622 if(er
->rc
>= E_NOTFOUND
) { return; }
624 //cacheex=2 mode: push (server->remote)
626 cs_readlock(__func__
, &clientlist_lock
);
627 for(cl
= first_client
->next
; cl
; cl
= cl
->next
)
629 if(check_client(cl
) && er
->cacheex_src
!= cl
)
631 if(get_module(cl
)->num
== R_CSP
) // always send to csp cl
633 if(!er
->cacheex_src
|| cfg
.csp
.allow_reforward
) { cacheex_cache_push_to_client(cl
, er
); } // but not if the origin was cacheex (might loop)
635 else if(cl
->typ
== 'c' && !cl
->dup
&& cl
->account
&& cl
->account
->cacheex
.mode
== 2) // send cache over user
637 if(get_module(cl
)->c_cache_push
// cache-push able
638 && (!er
->grp
|| (cl
->grp
& er
->grp
)
639 #ifdef CS_CACHEEX_AIO
640 || (er
->localgenerated
&& ((cl
->grp
& cfg
.cacheex_push_lg_groups
) && strcmp(username(cl
), username(er
->cacheex_src
))))
643 /**** OUTGOING FILTER CHECK ***/
644 && (!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
645 && (!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
646 && (!cl
->account
->cacheex
.drop_csp
|| checkECMD5(er
)) // cacheex_drop_csp-check
647 && chk_ctab(er
->caid
, &cl
->ctab
) // Caid-check
648 && (!checkECMD5(er
) || chk_ident_filter(er
->caid
, er
->prid
, &cl
->ftab
)) // Ident-check (not for csp: prid=0 always!)
649 && chk_srvid(cl
, er
) // Service-check
650 && chk_csp_ctab(er
, &cl
->account
->cacheex
.filter_caidtab
) // cacheex_ecm_filter
651 #ifdef CS_CACHEEX_AIO
652 && (er
->localgenerated
// lg-flag-check
653 || chk_srvid_localgenerated_only_exception(er
) // lg-only-service-exception
654 || !(cl
->account
->cacheex
.localgenerated_only
// usr-lg-only
656 (cl
->account
->cacheex
.feature_bitfield
& 64) // cx-aio >= 9.2.6 => check ftab
657 && (chk_lg_only(er
, &cl
->account
->cacheex
.lg_only_tab
) // usr-lg-only-ftab (feature 64)
658 || chk_lg_only(er
, &cfg
.cacheex_lg_only_tab
)) // global-lg-only-ftab (feature 64)
662 && (chk_cwcheck(er
, cl
->account
->cacheex
.cw_check_for_push
)) // check cw_check-counter if enabled
663 && chk_nopushafter(er
->caid
, &cl
->account
->cacheex
.cacheex_nopushafter_tab
, er
->ecm_time
) // no push after check
667 cacheex_cache_push_to_client(cl
, er
);
672 cs_readunlock(__func__
, &clientlist_lock
);
674 //cacheex=3 mode: reverse push (reader->server)
675 cs_readlock(__func__
, &readerlist_lock
);
676 cs_readlock(__func__
, &clientlist_lock
);
677 struct s_reader
*rdr
;
678 for(rdr
= first_active_reader
; rdr
; rdr
= rdr
->next
)
681 if(check_client(cl
) && er
->cacheex_src
!= cl
&& rdr
->cacheex
.mode
== 3) // send cache over reader
683 if(rdr
->ph
.c_cache_push
// cache-push able
684 && (!er
->grp
|| (rdr
->grp
& er
->grp
)
685 #ifdef CS_CACHEEX_AIO
686 || (er
->localgenerated
&& ((rdr
->grp
& cfg
.cacheex_push_lg_groups
) && strcmp(username(cl
), username(er
->cacheex_src
))))
689 /**** OUTGOING FILTER CHECK ***/
690 && (!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
691 && (!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
692 && (!rdr
->cacheex
.drop_csp
|| checkECMD5(er
)) // cacheex_drop_csp-check
693 && chk_ctab(er
->caid
, &rdr
->ctab
) // Caid-check
694 && (!checkECMD5(er
) || chk_ident_filter(er
->caid
, er
->prid
, &rdr
->ftab
)) // Ident-check (not for csp: prid=0 always!)
695 && chk_srvid(cl
, er
) // Service-check
696 && chk_csp_ctab(er
, &rdr
->cacheex
.filter_caidtab
) // cacheex_ecm_filter
697 #ifdef CS_CACHEEX_AIO
698 && (er
->localgenerated
// lg-only-check
699 || chk_srvid_localgenerated_only_exception(er
) // service-exception
700 || !(rdr
->cacheex
.localgenerated_only
// rdr-lg-only
702 (rdr
->cacheex
.feature_bitfield
& 64) // cx-aio >= 9.2.6 => check ftab
703 && (chk_lg_only(er
, &rdr
->cacheex
.lg_only_tab
) // rdr-lg-only-ftab (feature 64)
704 || chk_lg_only(er
, &cfg
.cacheex_lg_only_tab
)) // global-lg-only-ftab (feature 64)
708 && (chk_cwcheck(er
, rdr
->cacheex
.cw_check_for_push
)) // check cw_check-counter if enabled
709 && chk_nopushafter(er
->caid
, &rdr
->cacheex
.cacheex_nopushafter_tab
, er
->ecm_time
)
711 ) // no push after check
713 cacheex_cache_push_to_client(cl
, er
);
717 cs_readunlock(__func__
, &clientlist_lock
);
718 cs_readunlock(__func__
, &readerlist_lock
);
721 /**** INCOMING FILTER CHECK ***/
722 uint8_t check_cacheex_filter(struct s_client
*cl
, ECM_REQUEST
*er
)
725 if(check_client(cl
) && cl
->typ
== 'p' && cl
->reader
&& cl
->reader
->cacheex
.mode
== 2
726 && (!cl
->reader
->cacheex
.drop_csp
|| checkECMD5(er
)) // cacheex_drop_csp-check
727 && chk_ctab(er
->caid
, &cl
->reader
->ctab
) // Caid-check
728 && (!checkECMD5(er
) || chk_ident_filter(er
->caid
, er
->prid
, &cl
->reader
->ftab
)) // Ident-check (not for csp: prid=0 always!)
729 && chk_srvid(cl
, er
)) // Service-check
734 if(check_client(cl
) && cl
->typ
== 'c' && cl
->account
&& cl
->account
->cacheex
.mode
== 3
735 && (!cl
->account
->cacheex
.drop_csp
|| checkECMD5(er
)) // cacheex_drop_csp-check
736 && chk_ctab(er
->caid
, &cl
->ctab
) // Caid-check
737 && (!checkECMD5(er
) || chk_ident_filter(er
->caid
, er
->prid
, &cl
->ftab
)) // Ident-check (not for csp: prid=0 always!)
738 && chk_srvid(cl
, er
)) // Service-check
746 static struct s_cacheex_matcher
*is_cacheex_matcher_matching(ECM_REQUEST
*from_er
, ECM_REQUEST
*to_er
)
748 struct s_cacheex_matcher
*entry
= cfg
.cacheex_matcher
;
749 int8_t v_ok
= (from_er
&& to_er
) ? 2 : 1;
754 && (!entry
->caid
|| entry
->caid
== from_er
->caid
)
755 && (!entry
->provid
|| entry
->provid
== from_er
->prid
)
756 && (!entry
->srvid
|| entry
->srvid
== from_er
->srvid
)
757 && (!entry
->chid
|| entry
->chid
== from_er
->chid
)
758 && (!entry
->pid
|| entry
->pid
== from_er
->pid
)
759 && (!entry
->ecmlen
|| entry
->ecmlen
== from_er
->ecmlen
))
763 && (!entry
->to_caid
|| entry
->to_caid
== to_er
->caid
)
764 && (!entry
->to_provid
|| entry
->to_provid
== to_er
->prid
)
765 && (!entry
->to_srvid
|| entry
->to_srvid
== to_er
->srvid
)
766 && (!entry
->to_chid
|| entry
->to_chid
== to_er
->chid
)
767 && (!entry
->to_pid
|| entry
->to_pid
== to_er
->pid
)
768 && (!entry
->to_ecmlen
|| entry
->to_ecmlen
== to_er
->ecmlen
))
773 if(!from_er
|| !to_er
|| from_er
->srvid
== to_er
->srvid
)
781 bool cacheex_is_match_alias(struct s_client
*cl
, ECM_REQUEST
*er
)
783 return check_client(cl
) && cl
->account
&& cl
->account
->cacheex
.mode
== 1 && is_cacheex_matcher_matching(NULL
, er
);
787 static void log_cacheex_cw(ECM_REQUEST
*er
, char *reason
)
790 uint8_t remotenodeid
[8];
791 data
= ll_last_element(er
->csp_lastnodes
);
793 { memcpy(remotenodeid
, data
, 8); }
795 { memset(remotenodeid
, 0 , 8); }
798 format_ecm(er
, buf_ecm
, 109);
799 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",
800 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);
804 // check if sky_ger 64 bit CW has valid checksum bytes and therefore is probably invalid
805 uint8_t check_nds_cwex(ECM_REQUEST
*er
)
809 uint8_t oe
= checkCWpart(er
->cw
, 0) ? 0 : 8;
810 for(k
= 0; k
< 8; k
+= 4)
812 csum
= ((er
->cw
[k
+ oe
] + er
->cw
[k
+ oe
+ 1] + er
->cw
[k
+ oe
+ 2]) & 0xff);
813 if(er
->cw
[k
+ oe
+ 3] == csum
)
825 static int32_t cacheex_add_to_cache_int(struct s_client
*cl
, ECM_REQUEST
*er
, int8_t csp
)
827 if(er
->rc
>= E_NOTFOUND
) { return 0; }
831 if(!csp
&& cl
->reader
&& cl
->reader
->cacheex
.mode
!= 2) //from reader
833 cs_log_dbg(D_CACHEEX
, "CACHEX received, but disabled for %s", username(cl
));
836 if(!csp
&& !cl
->reader
&& cl
->account
&& cl
->account
->cacheex
.mode
!= 3) //from user
838 cs_log_dbg(D_CACHEEX
, "CACHEX received, but disabled for %s", username(cl
));
841 if(!csp
&& !cl
->reader
&& !cl
->account
) //not active!
843 cs_log_dbg(D_CACHEEX
, "CACHEX received, but invalid client state %s", username(cl
));
847 if(!cfg
.disablecrccws
&& ((cl
->typ
== 'c' && cl
->account
&& !cl
->account
->disablecrccacheex
) || ( cl
->typ
== 'p' && cl
->reader
&& !cl
->reader
->disablecrccws
)))
849 uint8_t selectedForIgnChecksum
= chk_if_ignore_checksum(er
, &cfg
.disablecrccws_only_for
);
852 selectedForIgnChecksum
+= chk_if_ignore_checksum(er
, &cl
->account
->disablecrccacheex_only_for
);
856 selectedForIgnChecksum
+= chk_if_ignore_checksum(er
, &cl
->reader
->disablecrccws_only_for
);
858 if(!selectedForIgnChecksum
)
861 for(i
= 0; i
< 16; i
+= 4)
863 c
= ((er
->cw
[i
] + er
->cw
[i
+ 1] + er
->cw
[i
+ 2]) & 0xff);
865 if(er
->cw
[i
+ 3] != c
)
867 cs_log_dump_dbg(D_CACHEEX
, er
->cw
, 16, "push received cw with chksum error from %s", csp
? "csp" : username(cl
));
870 { cl
->account
->cwcacheexerr
++; }
877 #ifdef CS_CACHEEX_AIO
878 if(caid_is_videoguard(er
->caid
))
880 if(cl
->typ
== 'p' && chk_if_ignore_checksum(er
, &cl
->reader
->disablecrccws_only_for
) && !chk_srvid_disablecrccws_only_for_exception(er
))
882 if(check_nds_cwex(er
))
884 if(check_client(cl
) && cl
->reader
&& cl
->reader
->dropbadcws
)
886 if (((D_CACHEEX
) & cs_dblevel
)) // avoid useless operations if debug is not enabled
888 uint8_t remotenodeid
[8];
889 cacheex_get_srcnodeid(er
, remotenodeid
);
891 cs_log_dbg(D_CACHEEX
, "Probably got pushed bad CW from cacheex reader: %s, caid %04X, srvid %04X - dropping CW, lg: %i, hop: %i, src-nodeid %" PRIu64
"X", cl
->reader
->label
, er
->caid
, er
->srvid
, er
->localgenerated
, ll_count(er
->csp_lastnodes
), er
->csp_lastnodes
? cacheex_node_id(remotenodeid
): 0);
897 if (((D_CACHEEX
) & cs_dblevel
)) // avoid useless operations if debug is not enabled
899 uint8_t remotenodeid
[8];
900 cacheex_get_srcnodeid(er
, remotenodeid
);
902 cs_log_dbg(D_CACHEEX
, "Probably got pushed bad CW from cacheex reader: %s, caid %04X, srvid %04X, lg: %i, hop: %i, src-nodeid %" PRIu64
"X", cl
->reader
->label
, er
->caid
, er
->srvid
, er
->localgenerated
, ll_count(er
->csp_lastnodes
), er
->csp_lastnodes
? cacheex_node_id(remotenodeid
): 0);
908 if(cl
->typ
== 'c' && chk_if_ignore_checksum(er
, &cl
->account
->disablecrccacheex_only_for
) && !chk_srvid_disablecrccws_only_for_exception(er
))
910 if(check_nds_cwex(er
))
912 if (((D_CACHEEX
) & cs_dblevel
)) // avoid useless operations if debug is not enabled
914 uint8_t remotenodeid
[8];
915 cacheex_get_srcnodeid(er
, remotenodeid
);
917 cs_log_dbg(D_CACHEEX
, "Probably got bad CW from cacheex user: %s, caid %04X, srvid %04X, lg: %i, hop: %i, src-nodeid %" PRIu64
"X", username(cl
), er
->caid
, er
->srvid
, er
->localgenerated
, ll_count(er
->csp_lastnodes
), er
->csp_lastnodes
? cacheex_node_id(remotenodeid
): 0);
924 // Skip check for BISS1 - cw could be indeed zero
925 // Skip check for BISS2 - we use the extended cw, so the "simple" cw is always zero
926 if(chk_is_null_CW(er
->cw
) && !caid_is_biss(er
->caid
))
928 cs_log_dump_dbg(D_CACHEEX
, er
->cw
, 16, "push received null cw from %s", csp
? "csp" : username(cl
));
931 { cl
->account
->cwcacheexerr
++; }
935 // Don't check for BISS1 and BISS2 mode 1/E or fake caid (ECM is fake for them)
936 // Don't check for BISS2 mode CA (ECM table is always 0x80)
937 if(!caid_is_biss(er
->caid
) && !caid_is_fake(er
->caid
) && get_odd_even(er
) == 0)
939 cs_log_dbg(D_CACHEEX
, "push received ecm with null odd/even byte from %s", csp
? "csp" : username(cl
));
942 { cl
->account
->cwcacheexerr
++; }
946 if(!chk_halfCW(er
, er
->cw
))
949 if(cs_dblevel
& D_CACHEEX
)
951 log_cacheex_cw(er
, "bad half cw");
956 { cl
->account
->cwcacheexerr
++; }
960 if((csp
&& cfg
.csp
.block_fakecws
) || (cl
->reader
&& cl
->reader
->cacheex
.block_fakecws
)
961 || (!cl
->reader
&& cl
->account
&& cl
->account
->cacheex
.block_fakecws
))
963 if(chk_is_fakecw(er
->cw
))
965 cs_log_dbg(D_CACHEEX
, "push received fake cw from %s", csp
? "csp" : username(cl
));
968 { cl
->account
->cwcacheexerr
++; }
973 er
->grp
|= cl
->grp
; // ok for mode2 reader too: cl->reader->grp
975 er
->cacheex_src
= cl
;
976 er
->selected_reader
= cl
->reader
;
977 er
->client
= NULL
; // No Owner! So no fallback!
983 { cl
->account
->cwcacheexgot
++; }
984 first_client
->cwcacheexgot
++;
985 #ifdef CS_CACHEEX_AIO
986 if(er
->localgenerated
)
988 cl
->cwcacheexgotlg
++;
990 cl
->account
->cwcacheexgotlg
++;
991 first_client
->cwcacheexgotlg
++;
996 cacheex_add_hitcache(cl
, er
); // we have to call it before add_cache, because in chk_process we could remove it!
998 #ifdef CS_CACHEEX_AIO
999 cacheex_add_stats(cl
, er
->caid
, er
->srvid
, er
->prid
, 1, er
->localgenerated
);
1001 cacheex_add_stats(cl
, er
->caid
, er
->srvid
, er
->prid
, 1);
1004 cs_writelock(__func__
, &ecm_pushed_deleted_lock
);
1005 er
->next
= ecm_pushed_deleted
;
1006 ecm_pushed_deleted
= er
;
1007 cs_writeunlock(__func__
, &ecm_pushed_deleted_lock
);
1009 return 1; // NO free, we have to wait cache push out stuff ends.
1012 void cacheex_add_to_cache(struct s_client
*cl
, ECM_REQUEST
*er
)
1014 er
->from_cacheex
= 1;
1015 if(!cacheex_add_to_cache_int(cl
, er
, 0))
1016 { free_push_in_ecm(er
); }
1019 void cacheex_add_to_cache_from_csp(struct s_client
*cl
, ECM_REQUEST
*er
)
1021 if(!cacheex_add_to_cache_int(cl
, er
, 1))
1022 { free_push_in_ecm(er
); }
1026 //caid:prov:srvid:pid:chid:ecmlen=caid:prov:srvid:pid:chid:ecmlen[,validfrom,validto]
1027 //validfrom: default=-2000
1028 //validto: default=4000
1029 //valid time if found in cache
1030 static struct s_cacheex_matcher
*cacheex_matcher_read_int(void)
1032 FILE *fp
= open_config_file(cs_cacheex_matcher
);
1038 int32_t i
, ret
, count
= 0;
1039 struct s_cacheex_matcher
*new_cacheex_matcher
= NULL
, *entry
, *last
= NULL
;
1042 while(fgets(token
, sizeof(token
), fp
))
1045 if(cs_strlen(token
) <= 1) { continue; }
1046 if(token
[0] == '#' || token
[0] == '/') { continue; }
1047 if(cs_strlen(token
) > 100) { continue; }
1049 for(i
= 0; i
< (int)cs_strlen(token
); i
++)
1051 if((token
[i
] == ':' || token
[i
] == ' ') && token
[i
+ 1] == ':')
1053 memmove(token
+ i
+ 2, token
+ i
+ 1, cs_strlen(token
) - i
+ 1);
1056 if(token
[i
] == '#' || token
[i
] == '/')
1064 uint32_t caid
= 0, provid
= 0, srvid
= 0, pid
= 0, chid
= 0, ecmlen
= 0;
1065 uint32_t to_caid
= 0, to_provid
= 0, to_srvid
= 0, to_pid
= 0, to_chid
= 0, to_ecmlen
= 0;
1066 int32_t valid_from
= -2000, valid_to
= 4000;
1068 ret
= sscanf(token
, "%c:%4x:%6x:%4x:%4x:%4x:%4X=%4x:%6x:%4x:%4x:%4x:%4X,%4d,%4d",
1070 &caid
, &provid
, &srvid
, &pid
, &chid
, &ecmlen
,
1071 &to_caid
, &to_provid
, &to_srvid
, &to_pid
, &to_chid
, &to_ecmlen
,
1072 &valid_from
, &valid_to
);
1074 type
= tolower(type
);
1076 if(ret
< 7 || type
!= 'm')
1079 if(!cs_malloc(&entry
, sizeof(struct s_cacheex_matcher
)))
1082 return new_cacheex_matcher
;
1088 entry
->provid
= provid
;
1089 entry
->srvid
= srvid
;
1092 entry
->ecmlen
= ecmlen
;
1093 entry
->to_caid
= to_caid
;
1094 entry
->to_provid
= to_provid
;
1095 entry
->to_srvid
= to_srvid
;
1096 entry
->to_pid
= to_pid
;
1097 entry
->to_chid
= to_chid
;
1098 entry
->to_ecmlen
= to_ecmlen
;
1099 entry
->valid_from
= valid_from
;
1100 entry
->valid_to
= valid_to
;
1102 cs_log_dbg(D_TRACE
, "cacheex-matcher: %c: %04X@%06X:%04X:%04X:%04X:%02X = %04X@%06X:%04X:%04X:%04X:%02X valid %d/%d",
1103 entry
->type
, entry
->caid
, entry
->provid
, entry
->srvid
, entry
->pid
, entry
->chid
, entry
->ecmlen
,
1104 entry
->to_caid
, entry
->to_provid
, entry
->to_srvid
, entry
->to_pid
, entry
->to_chid
, entry
->to_ecmlen
,
1105 entry
->valid_from
, entry
->valid_to
);
1107 if(!new_cacheex_matcher
)
1109 new_cacheex_matcher
= entry
;
1110 last
= new_cacheex_matcher
;
1120 { cs_log("%d entries read from %s", count
, cs_cacheex_matcher
); }
1124 return new_cacheex_matcher
;
1127 void cacheex_load_config_file(void)
1129 struct s_cacheex_matcher
*entry
, *old_list
;
1131 old_list
= cfg
.cacheex_matcher
;
1132 cfg
.cacheex_matcher
= cacheex_matcher_read_int();
1136 entry
= old_list
->next
;
1142 CWCHECK
get_cwcheck(ECM_REQUEST
*er
)
1146 int16_t counter
= 1;
1148 for(i
= 0; i
< cfg
.cacheex_cwcheck_tab
.cwchecknum
; i
++)
1150 CWCHECKTAB_DATA
*d
= &cfg
.cacheex_cwcheck_tab
.cwcheckdata
[i
];
1152 if(i
== 0 && d
->caid
<= 0)
1155 counter
= d
->counter
;
1156 continue; //check other, only valid for unset
1159 if(d
->caid
== er
->caid
|| d
->caid
== er
->caid
>> 8 || ((d
->cmask
>= 0 && (er
->caid
& d
->cmask
) == d
->caid
) || d
->caid
== -1))
1161 if((d
->prid
>= 0 && d
->prid
== (int32_t)er
->prid
) || d
->prid
== -1)
1163 if((d
->srvid
>= 0 && d
->srvid
== er
->srvid
) || d
->srvid
== -1)
1166 counter
= d
->counter
;
1174 //check for correct values
1175 if(mode
>2 || mode
<0) mode
=0;
1176 if(counter
<1) counter
=1;
1179 memset(&check_cw
, 0, sizeof(CWCHECK
));
1180 check_cw
.mode
= mode
;
1181 check_cw
.counter
= counter
;
1186 uint16_t get_cacheex_mode1_delay(ECM_REQUEST
*er
)
1188 return caidvaluetab_get_value(&cfg
.cacheex_mode1_delay_tab
, er
->caid
, 0);
1191 uint32_t get_cacheex_wait_time(ECM_REQUEST
*er
, struct s_client
*cl
)
1193 int32_t i
, dwtime
= -1, awtime
= -1;
1195 for(i
= 0; i
< cfg
.cacheex_wait_timetab
.cevnum
; i
++)
1197 CECSPVALUETAB_DATA
*d
= &cfg
.cacheex_wait_timetab
.cevdata
[i
];
1199 if(i
== 0 && d
->caid
<= 0)
1203 continue; //check other, only valid for unset
1206 if(d
->caid
== er
->caid
|| d
->caid
== er
->caid
>> 8 || ((d
->cmask
>= 0 && (er
->caid
& d
->cmask
) == d
->caid
) || d
->caid
== -1))
1208 if((d
->prid
>= 0 && d
->prid
== (int32_t)er
->prid
) || d
->prid
== -1)
1210 if((d
->srvid
>= 0 && d
->srvid
== er
->srvid
) || d
->srvid
== -1)
1221 if(awtime
> 0 && (dwtime
<= 0 || awtime
==dwtime
) ) //if awtime==dwtime useless check hitcache
1231 if(awtime
> 0 || dwtime
> 0)
1233 //if found last in cache return dynwaittime else alwayswaittime
1234 if(cacheex_check_hitcache(er
,cl
))
1235 { return dwtime
>= awtime
? dwtime
: awtime
; }
1237 { return awtime
> 0 ? awtime
: 0; }
1243 int32_t chk_csp_ctab(ECM_REQUEST
*er
, CECSPVALUETAB
*tab
)
1245 if(!er
->caid
|| !tab
->cevnum
)
1246 { return 1; } // nothing setup we add all
1248 for(i
= 0; i
< tab
->cevnum
; i
++)
1250 CECSPVALUETAB_DATA
*d
= &tab
->cevdata
[i
];
1253 if(d
->caid
== er
->caid
|| d
->caid
== er
->caid
>> 8 || ((d
->cmask
>= 0 && (er
->caid
& d
->cmask
) == d
->caid
) || d
->caid
== -1))
1255 if((d
->prid
>= 0 && d
->prid
== (int32_t)er
->prid
) || d
->prid
== -1)
1257 if((d
->srvid
>= 0 && d
->srvid
== er
->srvid
) || d
->srvid
== -1)
1268 void cacheex_push_out(struct s_client
*cl
, ECM_REQUEST
*er
)
1270 int32_t res
= 0, stats
= -1;
1271 struct s_reader
*reader
= cl
->reader
;
1272 struct s_module
*module
= get_module(cl
);
1274 // cc-nodeid-list-check
1277 if(reader
->ph
.c_cache_push_chk
&& !reader
->ph
.c_cache_push_chk(cl
, er
))
1279 res
= reader
->ph
.c_cache_push(cl
, er
);
1280 #ifdef CS_CACHEEX_AIO
1281 stats
= cacheex_add_stats(cl
, er
->caid
, er
->srvid
, er
->prid
, 0, er
->localgenerated
);
1283 stats
= cacheex_add_stats(cl
, er
->caid
, er
->srvid
, er
->prid
, 0);
1288 if(module
->c_cache_push_chk
&& !module
->c_cache_push_chk(cl
, er
))
1290 res
= module
->c_cache_push(cl
, er
);
1292 debug_ecm(D_CACHEEX
, "pushed ECM %s to %s res %d stats %d", buf
, username(cl
), res
, stats
);
1293 cl
->cwcacheexpush
++;
1295 { cl
->account
->cwcacheexpush
++; }
1296 first_client
->cwcacheexpush
++;
1298 #ifdef CS_CACHEEX_AIO
1299 if(er
->localgenerated
)
1301 cl
->cwcacheexpushlg
++;
1303 cl
->account
->cwcacheexpushlg
++;
1304 first_client
->cwcacheexpushlg
++;
1309 bool cacheex_check_queue_length(struct s_client
*cl
)
1311 // Avoid full running queues:
1312 if(ll_count(cl
->joblist
) <= 2000)
1315 cs_log_dbg(D_TRACE
, "WARNING: job queue %s %s has more than 2000 jobs! count=%d, dropped!",
1316 cl
->typ
== 'c' ? "client" : "reader", username(cl
), ll_count(cl
->joblist
));
1319 SAFE_MUTEX_LOCK(&cl
->thread_lock
);
1320 if(cl
&& !cl
->kill
&& cl
->thread
&& cl
->thread_active
)
1322 // Just test for invalid thread id:
1323 if(pthread_detach(cl
->thread
) == ESRCH
)
1325 cl
->thread_active
= 0;
1326 cs_log_dbg(D_TRACE
, "WARNING: %s %s thread died!", cl
->typ
== 'c' ? "client" : "reader", username(cl
));
1329 SAFE_MUTEX_UNLOCK(&cl
->thread_lock
);
1333 void cacheex_mode1_delay(ECM_REQUEST
*er
)
1335 if(!er
->cacheex_wait_time_expired
&& er
->cacheex_mode1_delay
1336 && er
->cacheex_reader_count
> 0 && !er
->stage
&& er
->rc
>= E_UNHANDLED
)
1338 cs_log_dbg(D_LB
, "{client %s, caid %04X, prid %06X, srvid %04X} cacheex_mode1_delay timeout! ",
1339 (check_client(er
->client
) ? er
->client
->account
->usr
: "-"), er
->caid
, er
->prid
, er
->srvid
);
1341 // setting stop_stage=1, we request only cacheex mode 1 readers. Others are requested at cacheex timeout!
1342 request_cw_from_readers(er
, 1);
1346 void cacheex_timeout(ECM_REQUEST
*er
)
1348 if(er
->cacheex_wait_time_expired
)
1350 er
->cacheex_wait_time_expired
= 1;
1351 if(er
->rc
>= E_UNHANDLED
)
1353 cs_log_dbg(D_LB
, "{client %s, caid %04X, prid %06X, srvid %04X} cacheex timeout! ",
1354 (check_client(er
->client
) ? er
->client
->account
->usr
: "-"), er
->caid
, er
->prid
, er
->srvid
);
1356 #ifdef CS_CACHEEX_AIO
1360 memset(&search
, 0, sizeof(HIT_KEY
));
1361 search
.caid
= er
->caid
;
1362 search
.prid
= er
->prid
;
1363 search
.srvid
= er
->srvid
;
1365 SAFE_RWLOCK_WRLOCK(&hitcache_lock
);
1367 result
= find_hash_table(&ht_hitcache
, &search
, sizeof(HIT_KEY
), &cacheex_compare_hitkey
);
1370 if(cfg
.waittime_block_start
&& (result
->waittime_block
<= cfg
.waittime_block_start
))
1372 result
->waittime_block
++;
1373 cs_log_dbg(D_LB
, "{client %s, caid %04X, prid %06X, srvid %04X} waittime_block count: %u ",
1374 (check_client(er
->client
) ? er
->client
->account
->usr
: "-"), er
->caid
, er
->prid
, er
->srvid
, result
->waittime_block
);
1378 SAFE_RWLOCK_UNLOCK(&hitcache_lock
);
1380 // if check_cw mode=0, first try to get cw from cache without check counter!
1381 CWCHECK check_cw
= get_cwcheck(er
);
1384 struct ecm_request_t
*ecm
= NULL
;
1385 ecm
= check_cache(er
, er
->client
);
1387 if(ecm
) // found in cache
1389 struct s_write_from_cache
*wfc
= NULL
;
1390 if(!cs_malloc(&wfc
, sizeof(struct s_write_from_cache
)))
1396 wfc
->er_cache
= ecm
;
1397 if(!add_job(er
->client
, ACTION_ECM_ANSWER_CACHE
, wfc
, sizeof(struct s_write_from_cache
))) // write_ecm_answer_fromcache
1403 // check if "normal" readers selected, if not send NOT FOUND!
1404 // cacheex1-client (having always no "normal" reader),
1405 // or not-cacheex-1 client with no normal readers available (or filtered by LB)
1406 if((er
->reader_count
+ er
->fallback_reader_count
- er
->cacheex_reader_count
) <= 0)
1408 if(!cfg
.wait_until_ctimeout
)
1410 er
->rc
= E_NOTFOUND
;
1411 er
->selected_reader
= NULL
;
1413 cs_log_dbg(D_LB
, "{client %s, caid %04X, prid %06X, srvid %04X} cacheex timeout: NO \"normal\" readers... not_found! ",
1414 (check_client(er
->client
) ? er
->client
->account
->usr
: "-"), er
->caid
, er
->prid
, er
->srvid
);
1416 send_dcw(er
->client
, er
);
1424 debug_ecm(D_TRACE
, "request for %s %s", username(er
->client
), buf
);
1425 request_cw_from_readers(er
, 0);
1431 #ifdef CS_CACHEEX_AIO
1432 char* cxaio_ftab_to_buf(FTAB
*lg_only_ftab
)
1434 int32_t i
, k
, l
= 0, strncat_sz
= 0;
1440 // get size of return-val
1441 for(i
= 0; i
< lg_only_ftab
->nfilts
; i
++)
1444 l
+= 2; // nprid-counter
1445 l
+= 6 * lg_only_ftab
->filts
[i
].nprids
; // prid/s
1447 if(!lg_only_ftab
->filts
[i
].nprids
)
1453 if(!cs_malloc(&ret
, l
* sizeof(char) + sizeof(char))) {
1457 strncat_sz
+= l
* sizeof(char) + sizeof(char);
1459 for(i
= 0; i
< lg_only_ftab
->nfilts
; i
++)
1461 snprintf(caid
, 5, "%04X", lg_only_ftab
->filts
[i
].caid
);
1462 if (!cs_strncat(ret
, caid
, strncat_sz
)) {
1466 if(!lg_only_ftab
->filts
[i
].nprids
)
1468 if (!cs_strncat(ret
, "01", strncat_sz
)) {
1471 snprintf(provid
, 7, "000000");
1472 if (!cs_strncat(ret
, provid
, strncat_sz
)) {
1478 snprintf(nprids
, 3, "%02X", lg_only_ftab
->filts
[i
].nprids
);
1479 if (!cs_strncat(ret
, nprids
, strncat_sz
)) {
1484 for(k
= 0; k
< lg_only_ftab
->filts
[i
].nprids
; k
++)
1486 snprintf(provid
, 7, "%06X", lg_only_ftab
->filts
[i
].prids
[k
]);
1487 if (!cs_strncat(ret
, provid
, strncat_sz
)) {
1495 FTAB
caidtab2ftab(CAIDTAB
*ctab
)
1499 memset(&ftab
, 0, sizeof(ftab
));
1501 for(i
=0; i
<ctab
->ctnum
; i
++)
1504 memset(&d
, 0, sizeof(d
));
1505 d
.caid
= ctab
->ctdata
[i
].caid
;
1506 d
.prids
[d
.nprids
] = NO_PROVID_VALUE
;
1508 ftab_add(&ftab
, &d
);
1513 void caidtab2ftab_add(CAIDTAB
*lgonly_ctab
, FTAB
*lgonly_tab
)
1516 for(j
= 0; j
< lgonly_ctab
->ctnum
; j
++)
1518 CAIDTAB_DATA
*d
= &lgonly_ctab
->ctdata
[j
];
1522 if(lgonly_tab
->nfilts
)
1524 for(k
= 0; (k
< lgonly_tab
->nfilts
); k
++)
1526 if(lgonly_tab
->filts
[k
].caid
!= 0 && lgonly_tab
->filts
[k
].caid
== d
->caid
)
1528 for(l
= 0; (l
< lgonly_tab
->filts
[k
].nprids
); l
++)
1530 if(lgonly_tab
->filts
[k
].prids
[l
] == NO_PROVID_VALUE
)
1538 lgonly_tab
->filts
[k
].nprids
= 1;
1539 lgonly_tab
->filts
[k
].prids
[0] = NO_PROVID_VALUE
;
1546 if(!rc
) // caid not found
1549 memset(&df
, 0, sizeof(df
));
1551 df
.prids
[0] = NO_PROVID_VALUE
;
1553 ftab_add(lgonly_tab
, &df
);