- fix Building without Nagra not possible at Nagra_Merlin https://trac.streamboard...
[oscam.git] / module-cacheex.c
blob04e27699d07476112bbebb24c2f998fcd1b79594
1 #define MODULE_LOG_PREFIX "cacheex"
3 #include "globals.h"
5 #ifdef CS_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"
21 #ifdef CS_CACHEEX_AIO
22 #include "oscam-array.h"
23 #endif
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 {
40 uint16_t caid;
41 uint32_t prid;
42 uint16_t srvid;
43 } HIT_KEY;
45 typedef struct cache_hit_t {
46 HIT_KEY key;
47 struct timeb time;
48 struct timeb max_hitcache_time;
49 uint64_t grp;
50 uint64_t grp_last_max_hitcache_time;
51 #ifdef CS_CACHEEX_AIO
52 int32_t waittime_block;
53 #endif
54 node ht_node;
55 node ll_node;
56 } CACHE_HIT;
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)
85 return 0;
87 return 1;
90 static int32_t cacheex_check_hitcache(ECM_REQUEST *er, struct s_client *cl)
92 CACHE_HIT *result;
93 HIT_KEY search;
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);
100 if(result){
101 struct timeb now;
102 cs_ftime(&now);
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
113 #endif
116 SAFE_RWLOCK_UNLOCK(&hitcache_lock);
117 return 1;
120 SAFE_RWLOCK_UNLOCK(&hitcache_lock);
121 return 0;
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
127 return;
128 if (!cfg.cacheex_wait_timetab.cevnum)
129 return;
130 uint32_t cacheex_wait_time = get_cacheex_wait_time(er,NULL);
131 if (!cacheex_wait_time)
132 return;
134 CACHE_HIT *result;
135 HIT_KEY search;
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;
156 #endif
157 add_hash_table(&ht_hitcache, &result->ht_node, &ll_hitcache, &result->ll_node, result, &result->key, sizeof(HIT_KEY));
161 if(result)
163 if(cl)
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)
176 HIT_KEY search;
177 CACHE_HIT *result;
179 memset(&search, 0, sizeof(HIT_KEY));
180 search.caid = er->caid;
181 search.prid = er->prid;
182 search.srvid = er->srvid;
184 if(cl && cl->grp)
186 result = find_hash_table(&ht_hitcache, &search, sizeof(HIT_KEY), &cacheex_compare_hitkey);
187 while(result)
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)
202 CACHE_HIT *cachehit;
203 node *i,*i_next;
204 struct timeb now;
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);
211 while (i)
213 i_next = i->next;
214 cachehit = get_data_from_node(i);
216 if(!cachehit)
218 i = i_next;
219 continue;
222 cs_ftime(&now);
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))
229 #endif
232 remove_elem_list(&ll_hitcache, &cachehit->ll_node);
233 remove_elem_hash_table(&ht_hitcache, &cachehit->ht_node);
234 NULLFREE(cachehit);
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++;
247 #endif
248 i = i_next;
250 SAFE_RWLOCK_UNLOCK(&hitcache_lock);
253 static int32_t cacheex_ecm_hash_calc(uint8_t *buf, int32_t n)
255 int32_t i, h = 0;
256 for(i = 0; i < n; i++)
258 h = 31 * h + buf[i];
260 return h;
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__);
294 time_t timeout;
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)
310 { break; }
312 if(er->rc < E_UNHANDLED || er->readers_timeout_check) // already answered
313 { continue; }
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
333 add_hitcache_er = 1;
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)
340 rdr = ea->reader;
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)!!!
353 if(add_hitcache_er)
355 cacheex_add_hitcache(cex_src, er);
361 else
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))
372 wfc = NULL;
373 if(!cs_malloc(&wfc, sizeof(struct s_write_from_cache)))
375 NULLFREE(ecm);
376 continue;
379 wfc->er_new = er;
380 wfc->er_cache = ecm;
382 if(!add_job(er->client, ACTION_ECM_ANSWER_CACHE, wfc, sizeof(struct s_write_from_cache))) // write_ecm_answer_fromcache
384 NULLFREE(ecm);
385 continue;
388 else
390 NULLFREE(ecm);
394 cs_readunlock(__func__, &ecmcache_lock);
395 cs_sleepms(10);
398 return NULL;
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);
410 #ifdef MODULE_CCCAM
411 memcpy(cacheex_peer_id, cc_node_id, 8);
412 #endif
413 #ifdef MODULE_CAMD35_TCP
414 memcpy(camd35_node_id, cacheex_peer_id, 8);
415 #endif
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;
426 #endif
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;
437 #endif
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
443 #endif
446 if(!cfg.cacheex_enable_stats)
447 { return -1; }
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
468 if(localgenerated)
469 cacheex_stats_entry->cache_count_lg++;
470 #endif
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
484 if(localgenerated)
485 cacheex_stats_entry->cache_count_lg = 1;
486 #endif
487 cacheex_stats_entry->cache_last = now;
488 cacheex_stats_entry->cache_direction = direction;
489 ll_iter_insert(&itr, cacheex_stats_entry);
490 return 1;
492 return 0;
495 int8_t cacheex_maxhop(struct s_client *cl)
497 int maxhop = 10;
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; }
502 return maxhop;
505 #ifdef CS_CACHEEX_AIO
506 int8_t cacheex_maxhop_lg(struct s_client *cl)
508 int max = 10;
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)
521 maxhop_lg = maxhop;
523 else
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)
539 maxhop_lg = maxhop;
541 else
543 maxhop_lg = cl->account->cacheex.maxhop_lg;
546 cl->account->cacheex.maxhop_lg = maxhop_lg;
548 return maxhop_lg;
550 #endif
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)
562 int8_t i;
563 for(i = 0; i < CS_ECMSTORESIZE; i++)
564 if(er->ecmd5[i]) { return 1; }
565 return 0;
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)
572 return 1;
574 CWCHECK check_cw;
575 check_cw = get_cwcheck(er);
577 if(check_cw.mode && check_cw.counter > 1)
579 if(er->cw_count >= check_cw.counter)
581 return 1;
583 else
585 cs_log_dbg(D_CACHEEX, "push denied - cacheex_check_cw.counter: %u > er->cw_count: %u", check_cw.counter, er->cw_count);
586 return 0;
589 else
591 return 1;
594 #endif
597 * cacheex modes:
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
607 * CW-flow: B->A
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
617 * CW-flow: B->A
620 void cacheex_cache_push(ECM_REQUEST *er)
622 if(er->rc >= E_NOTFOUND) { return; }
624 //cacheex=2 mode: push (server->remote)
625 struct s_client *cl;
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))))
641 #endif
642 ) // Group-check
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
655 || (
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
664 #endif
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)
680 cl = rdr->client;
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))))
687 #endif
688 ) // Group-check
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
701 || (
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)
710 #endif
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
731 return 1;
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
740 return 1;
742 free_ecm(er);
743 return 0;
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;
750 while(entry)
752 int8_t ok = 0;
753 if(from_er
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))
760 { ok++; }
762 if(to_er
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))
769 { ok++; }
771 if(ok == v_ok)
773 if(!from_er || !to_er || from_er->srvid == to_er->srvid)
774 { return entry; }
776 entry = entry->next;
778 return NULL;
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);
786 #ifdef WITH_DEBUG
787 static void log_cacheex_cw(ECM_REQUEST *er, char *reason)
789 uint8_t *data;
790 uint8_t remotenodeid[8];
791 data = ll_last_element(er->csp_lastnodes);
792 if(data)
793 { memcpy(remotenodeid, data, 8); }
794 else
795 { memset(remotenodeid, 0 , 8); }
797 char buf_ecm[109];
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);
802 #endif
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)
807 uint8_t k, csum;
808 uint8_t hit = 0;
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)
815 hit++;
818 if(hit > 1)
820 return 1;
822 return 0;
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; }
829 if(!cl)
830 { 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));
834 return 0;
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));
839 return 0;
841 if(!csp && !cl->reader && !cl->account) //not active!
843 cs_log_dbg(D_CACHEEX, "CACHEX received, but invalid client state %s", username(cl));
844 return 0;
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);
850 if(cl->typ == 'c')
852 selectedForIgnChecksum += chk_if_ignore_checksum(er, &cl->account->disablecrccacheex_only_for);
854 if(cl->typ == 'p')
856 selectedForIgnChecksum += chk_if_ignore_checksum(er, &cl->reader->disablecrccws_only_for);
858 if(!selectedForIgnChecksum)
860 uint8_t i, c;
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));
868 cl->cwcacheexerr++;
869 if(cl->account)
870 { cl->account->cwcacheexerr++; }
871 return 0;
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);
893 return 0;
895 else
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);
922 #endif
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));
929 cl->cwcacheexerr++;
930 if(cl->account)
931 { cl->account->cwcacheexerr++; }
932 return 0;
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));
940 cl->cwcacheexerr++;
941 if(cl->account)
942 { cl->account->cwcacheexerr++; }
943 return 0;
946 if(!chk_halfCW(er, er->cw))
948 #ifdef WITH_DEBUG
949 if(cs_dblevel & D_CACHEEX)
951 log_cacheex_cw(er, "bad half cw");
953 #endif
954 cl->cwcacheexerr++;
955 if(cl->account)
956 { cl->account->cwcacheexerr++; }
957 return 0;
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));
966 cl->cwcacheexerr++;
967 if(cl->account)
968 { cl->account->cwcacheexerr++; }
969 return 0;
973 er->grp |= cl->grp; // ok for mode2 reader too: cl->reader->grp
974 er->rc = E_CACHEEX;
975 er->cacheex_src = cl;
976 er->selected_reader = cl->reader;
977 er->client = NULL; // No Owner! So no fallback!
979 if(check_client(cl))
981 cl->cwcacheexgot++;
982 if(cl->account)
983 { cl->account->cwcacheexgot++; }
984 first_client->cwcacheexgot++;
985 #ifdef CS_CACHEEX_AIO
986 if(er->localgenerated)
988 cl->cwcacheexgotlg++;
989 if(cl->account)
990 cl->account->cwcacheexgotlg++;
991 first_client->cwcacheexgotlg++;
993 #endif
996 cacheex_add_hitcache(cl, er); // we have to call it before add_cache, because in chk_process we could remove it!
997 add_cache(er);
998 #ifdef CS_CACHEEX_AIO
999 cacheex_add_stats(cl, er->caid, er->srvid, er->prid, 1, er->localgenerated);
1000 #else
1001 cacheex_add_stats(cl, er->caid, er->srvid, er->prid, 1);
1002 #endif
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); }
1025 //Format:
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);
1033 if(!fp)
1034 { return NULL; }
1036 char token[1024];
1037 uint8_t type;
1038 int32_t i, ret, count = 0;
1039 struct s_cacheex_matcher *new_cacheex_matcher = NULL, *entry, *last = NULL;
1040 uint32_t line = 0;
1042 while(fgets(token, sizeof(token), fp))
1044 line++;
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);
1054 token[i + 1] = '0';
1056 if(token[i] == '#' || token[i] == '/')
1058 token[i] = '\0';
1059 break;
1063 type = 'm';
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",
1069 &type,
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')
1077 { continue; }
1079 if(!cs_malloc(&entry, sizeof(struct s_cacheex_matcher)))
1081 fclose(fp);
1082 return new_cacheex_matcher;
1084 count++;
1085 entry->line = line;
1086 entry->type = type;
1087 entry->caid = caid;
1088 entry->provid = provid;
1089 entry->srvid = srvid;
1090 entry->pid = pid;
1091 entry->chid = chid;
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;
1112 else
1114 last->next = entry;
1115 last = entry;
1119 if(count)
1120 { cs_log("%d entries read from %s", count, cs_cacheex_matcher); }
1122 fclose(fp);
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();
1134 while(old_list)
1136 entry = old_list->next;
1137 NULLFREE(old_list);
1138 old_list = entry;
1142 CWCHECK get_cwcheck(ECM_REQUEST *er)
1144 int32_t i;
1145 int8_t mode = 0;
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)
1154 mode = d->mode;
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)
1165 mode = d->mode;
1166 counter = d->counter;
1167 break;
1174 //check for correct values
1175 if(mode>2 || mode<0) mode=0;
1176 if(counter<1) counter=1;
1178 CWCHECK check_cw;
1179 memset(&check_cw, 0, sizeof(CWCHECK));
1180 check_cw.mode = mode;
1181 check_cw.counter = counter;
1183 return check_cw;
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)
1201 dwtime = d->dwtime;
1202 awtime = d->awtime;
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)
1212 dwtime = d->dwtime;
1213 awtime = d->awtime;
1214 break;
1221 if(awtime > 0 && (dwtime <= 0 || awtime==dwtime) ) //if awtime==dwtime useless check hitcache
1223 return awtime;
1225 if(cl == NULL)
1227 if(dwtime < 0)
1228 { dwtime = 0; }
1229 return dwtime;
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; }
1236 else
1237 { return awtime > 0 ? awtime : 0; }
1239 return 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
1247 int32_t i;
1248 for(i = 0; i < tab->cevnum; i++)
1250 CECSPVALUETAB_DATA *d = &tab->cevdata[i];
1251 if(d->caid > 0)
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)
1259 return 1;
1265 return 0;
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
1275 if(reader)
1277 if(reader->ph.c_cache_push_chk && !reader->ph.c_cache_push_chk(cl, er))
1278 return;
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);
1282 #else
1283 stats = cacheex_add_stats(cl, er->caid, er->srvid, er->prid, 0);
1284 #endif
1286 else
1288 if(module->c_cache_push_chk && !module->c_cache_push_chk(cl, er))
1289 return;
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++;
1294 if(cl->account)
1295 { cl->account->cwcacheexpush++; }
1296 first_client->cwcacheexpush++;
1298 #ifdef CS_CACHEEX_AIO
1299 if(er->localgenerated)
1301 cl->cwcacheexpushlg++;
1302 if(cl->account)
1303 cl->account->cwcacheexpushlg++;
1304 first_client->cwcacheexpushlg++;
1306 #endif
1309 bool cacheex_check_queue_length(struct s_client *cl)
1311 // Avoid full running queues:
1312 if(ll_count(cl->joblist) <= 2000)
1313 return 0;
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));
1318 // Thread down???
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);
1330 return 1;
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)
1349 return;
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
1357 CACHE_HIT *result;
1358 HIT_KEY search;
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);
1368 if(result)
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);
1379 #endif
1380 // if check_cw mode=0, first try to get cw from cache without check counter!
1381 CWCHECK check_cw = get_cwcheck(er);
1382 if(!check_cw.mode)
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)))
1392 NULLFREE(ecm);
1393 return;
1395 wfc->er_new = er;
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
1398 { NULLFREE(ecm); }
1399 return;
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;
1412 er->rcEx = 0;
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);
1417 return;
1420 else
1422 if(er->stage < 2)
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;
1435 char *ret;
1436 char caid[5];
1437 char provid[7];
1438 char nprids[3];
1440 // get size of return-val
1441 for(i = 0; i < lg_only_ftab->nfilts; i++)
1443 l += 4; // caid
1444 l += 2; // nprid-counter
1445 l += 6 * lg_only_ftab->filts[i].nprids; // prid/s
1447 if(!lg_only_ftab->filts[i].nprids)
1449 l += 6;
1453 if(!cs_malloc(&ret, l * sizeof(char) + sizeof(char))) {
1454 return "";
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)) {
1463 cs_log("FIXME!");
1466 if(!lg_only_ftab->filts[i].nprids)
1468 if (!cs_strncat(ret, "01", strncat_sz)) {
1469 cs_log("FIXME2!");
1471 snprintf(provid, 7, "000000");
1472 if (!cs_strncat(ret, provid, strncat_sz)) {
1473 cs_log("FIXME3!");
1476 else
1478 snprintf(nprids, 3, "%02X", lg_only_ftab->filts[i].nprids);
1479 if (!cs_strncat(ret, nprids, strncat_sz)) {
1480 cs_log("FIXME4!");
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)) {
1488 cs_log("FIXME5!");
1492 return ret;
1495 FTAB caidtab2ftab(CAIDTAB *ctab)
1497 int i;
1498 FTAB ftab;
1499 memset(&ftab, 0, sizeof(ftab));
1501 for(i=0; i<ctab->ctnum; i++)
1503 FILTER d;
1504 memset(&d, 0, sizeof(d));
1505 d.caid = ctab->ctdata[i].caid;
1506 d.prids[d.nprids] = NO_PROVID_VALUE;
1507 d.nprids++;
1508 ftab_add(&ftab, &d);
1510 return ftab;
1513 void caidtab2ftab_add(CAIDTAB *lgonly_ctab, FTAB *lgonly_tab)
1515 int j, k, l, rc;
1516 for(j = 0; j < lgonly_ctab->ctnum; j++)
1518 CAIDTAB_DATA *d = &lgonly_ctab->ctdata[j];
1519 if(d->caid)
1521 rc = 0;
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)
1532 rc = 1;
1533 break;
1536 if(!rc)
1538 lgonly_tab->filts[k].nprids = 1;
1539 lgonly_tab->filts[k].prids[0] = NO_PROVID_VALUE;
1540 rc = 1;
1542 break;
1546 if(!rc) // caid not found
1548 FILTER df;
1549 memset(&df, 0, sizeof(df));
1550 df.caid = d->caid;
1551 df.prids[0] = NO_PROVID_VALUE;
1552 df.nprids++;
1553 ftab_add(lgonly_tab, &df);
1558 #endif
1559 #endif