1 #define MODULE_LOG_PREFIX "stat"
6 #include "cscrypt/md5.h"
7 #include "module-cacheex.h"
8 #include "module-cccam.h"
9 #include "oscam-array.h"
10 #include "oscam-cache.h"
11 #include "oscam-conf-chk.h"
12 #include "oscam-chk.h"
13 #include "oscam-client.h"
14 #include "oscam-ecm.h"
15 #include "oscam-files.h"
16 #include "oscam-lock.h"
17 #include "oscam-string.h"
18 #include "oscam-time.h"
20 #define UNDEF_AVG_TIME 99999 //NOT set here 0 or small value! Could cause there reader get selected
21 #define MAX_ECM_SEND_CACHE 16
24 #define LB_FASTEST_READER_FIRST 1
25 #define LB_OLDEST_READER_FIRST 2
26 #define LB_LOWEST_USAGELEVEL 3
28 #define DEFAULT_LOCK_TIMEOUT 1000000
30 extern CS_MUTEX_LOCK ecmcache_lock
;
31 extern struct ecm_request_t
*ecmcwcache
;
33 static int32_t stat_load_save
;
35 static struct timeb last_housekeeping
;
39 stat_load_save
= -100;
42 if(cfg
.lb_nbest_readers
< 2)
43 { cfg
.lb_nbest_readers
= DEFAULT_NBEST
; }
44 if(cfg
.lb_nfb_readers
< 2)
45 { cfg
.lb_nfb_readers
= DEFAULT_NFB
; }
46 if(cfg
.lb_min_ecmcount
< 2)
47 { cfg
.lb_min_ecmcount
= DEFAULT_MIN_ECM_COUNT
; }
48 if(cfg
.lb_max_ecmcount
< 3)
49 { cfg
.lb_max_ecmcount
= DEFAULT_MAX_ECM_COUNT
; }
50 if(cfg
.lb_reopen_seconds
< 10)
51 { cfg
.lb_reopen_seconds
= DEFAULT_REOPEN_SECONDS
; }
52 if(cfg
.lb_retrylimit
< 0)
53 { cfg
.lb_retrylimit
= DEFAULT_RETRYLIMIT
; }
54 if(cfg
.lb_stat_cleanup
<= 0)
55 { cfg
.lb_stat_cleanup
= DEFAULT_LB_STAT_CLEANUP
; }
60 static uint32_t get_prid(uint16_t caid
, uint32_t prid
)
63 for(i
= 0; i
< cfg
.lb_noproviderforcaid
.ctnum
; i
++)
65 CAIDTAB_DATA
*d
= &cfg
.lb_noproviderforcaid
.ctdata
[i
];
66 uint16_t tcaid
= d
->caid
;
68 if((tcaid
== caid
) || (tcaid
< 0x0100 && (caid
>> 8) == tcaid
))
78 static void get_stat_query(ECM_REQUEST
*er
, STAT_QUERY
*q
)
80 memset(q
, 0, sizeof(STAT_QUERY
));
83 q
->prid
= get_prid(er
->caid
, er
->prid
);
86 q
->ecmlen
= er
->ecmlen
;
89 void load_stat_from_file(void)
99 get_tmp_dir_filename(buf
, sizeof(buf
), "stat");
103 { fname
= cfg
.lb_savepath
; }
105 file
= fopen(fname
, "r");
108 cs_log("loadbalancer: could not open %s for reading (errno=%d %s)", fname
, errno
, strerror(errno
));
112 if(!cs_malloc(&line
, LINESIZE
))
118 cs_log_dbg(D_LB
, "loadbalancer: load statistics from %s", fname
);
123 struct s_reader
*rdr
= NULL
;
130 char *ptr
, *saveptr1
= NULL
;
133 while(fgets(line
, LINESIZE
, file
))
135 if(!line
[0] || line
[0] == '#' || line
[0] == ';')
138 if(!cs_malloc(&s
, sizeof(READER_STAT
)))
141 //get type by evaluating first line:
144 if(strstr(line
, " rc ")) { type
= 2; }
148 if(type
== 1) //New format - faster parsing:
150 for(i
= 0, ptr
= strtok_r(line
, ",", &saveptr1
); ptr
&& i
< 12 ; ptr
= strtok_r(NULL
, ",", &saveptr1
), i
++)
155 strncpy(buf
, split
[0], sizeof(buf
) - 1);
156 s
->rc
= atoi(split
[1]);
157 s
->caid
= a2i(split
[2], 4);
158 s
->prid
= a2i(split
[3], 6);
159 s
->srvid
= a2i(split
[4], 4);
160 s
->chid
= a2i(split
[5], 4);
161 s
->time_avg
= atoi(split
[6]);
162 s
->ecm_count
= atoi(split
[7]);
163 s
->last_received
.time
= atol(split
[8]);
164 s
->fail_factor
= atoi(split
[9]);
165 s
->ecmlen
= a2i(split
[10], 2);
168 else //Old format - keep for compatibility:
170 i
= sscanf(line
, "%255s rc %04d caid %04hX prid %06X srvid %04hX time avg %d ms ecms %d last %ld fail %d len %02hX\n",
171 buf
, &s
->rc
, &s
->caid
, &s
->prid
, &s
->srvid
,
172 &s
->time_avg
, &s
->ecm_count
, &s
->last_received
.time
, &s
->fail_factor
, &s
->ecmlen
);
176 if(valid
&& s
->ecmlen
> 0)
179 if(rdr
== NULL
|| strcmp(buf
, rdr
->label
) != 0)
181 LL_ITER itr
= ll_iter_create(configured_readers
);
182 while((rdr
= ll_iter_next(&itr
)))
184 if(strcmp(rdr
->label
, buf
) == 0)
191 if(rdr
!= NULL
&& strcmp(buf
, rdr
->label
) == 0)
195 rdr
->lb_stat
= ll_create("lb_stat");
196 cs_lock_create(__func__
, &rdr
->lb_stat_lock
, rdr
->label
, DEFAULT_LOCK_TIMEOUT
);
199 ll_append(rdr
->lb_stat
, s
);
204 cs_log("loadbalancer: statistics could not be loaded for %s", buf
);
210 cs_log_dbg(D_LB
, "loadbalancer: statistics ERROR: %s rc=%d i=%d", buf
, s
->rc
, i
);
219 int64_t load_time
= comp_timeb(&te
, &ts
);
221 cs_log_dbg(D_LB
, "loadbalancer: statistics loaded %d records in %"PRId64
" ms", count
, load_time
);
225 void lb_destroy_stats(struct s_reader
*rdr
)
229 cs_lock_destroy(__func__
, &rdr
->lb_stat_lock
);
230 ll_destroy_data(&rdr
->lb_stat
);
234 * get statistic values for reader ridx and caid/prid/srvid/ecmlen
236 static READER_STAT
*get_stat_lock(struct s_reader
*rdr
, STAT_QUERY
*q
, int8_t lock
)
240 rdr
->lb_stat
= ll_create("lb_stat");
241 cs_lock_create(__func__
, &rdr
->lb_stat_lock
, rdr
->label
, DEFAULT_LOCK_TIMEOUT
);
244 if(lock
) { cs_readlock(__func__
, &rdr
->lb_stat_lock
); }
246 LL_ITER it
= ll_iter_create(rdr
->lb_stat
);
249 while((s
= ll_iter_next(&it
)))
252 if(s
->caid
== q
->caid
&& s
->prid
== q
->prid
&& s
->srvid
== q
->srvid
&& s
->chid
== q
->chid
)
254 if(s
->ecmlen
== q
->ecmlen
)
258 s
->ecmlen
= q
->ecmlen
;
261 if(!q
->ecmlen
) //Query without ecmlen from dvbapi
265 if(lock
) { cs_readunlock(__func__
, &rdr
->lb_stat_lock
); }
267 //Move stat to list start for faster access:
268 if (i
> 10 && s
&& !rdr
->lb_stat_busy
) {
269 if (lock
) cs_writelock(__func__
, &rdr
->lb_stat_lock
);
270 ll_iter_move_first(&it
);
271 if (lock
) cs_writeunlock(__func__
, &rdr
->lb_stat_lock
);
278 * get statistic values for reader ridx and caid/prid/srvid/ecmlen
280 static READER_STAT
*get_stat(struct s_reader
*rdr
, STAT_QUERY
*q
)
282 return get_stat_lock(rdr
, q
, 1);
286 * Calculates average time
288 static void calc_stat(READER_STAT
*s
)
290 int32_t i
, c
= 0, t
= 0;
291 for(i
= 0; i
< LB_MAX_STAT_TIME
; i
++)
293 if(s
->time_stat
[i
] > 0)
295 t
+= (int32_t)s
->time_stat
[i
];
300 { s
->time_avg
= UNDEF_AVG_TIME
; }
302 { s
->time_avg
= t
/ c
; }
306 * Saves statistik to /tmp/.oscam/stat.n where n is reader-index
308 static void save_stat_to_file_thread(void)
313 set_thread_name(__func__
);
318 get_tmp_dir_filename(buf
, sizeof(buf
), "stat");
322 { fname
= cfg
.lb_savepath
; }
324 FILE *file
= fopen(fname
, "w");
328 cs_log("can't write to file %s", fname
);
335 int32_t cleanup_timeout
= (cfg
.lb_stat_cleanup
* 60 * 60 * 1000);
338 struct s_reader
*rdr
;
339 LL_ITER itr
= ll_iter_create(configured_readers
);
340 while((rdr
= ll_iter_next(&itr
)))
345 rdr
->lb_stat_busy
= 1;
347 cs_writelock(__func__
, &rdr
->lb_stat_lock
);
348 LL_ITER it
= ll_iter_create(rdr
->lb_stat
);
350 while((s
= ll_iter_next(&it
)))
352 int64_t gone
= comp_timeb(&ts
, &s
->last_received
);
353 if(gone
> cleanup_timeout
|| !s
->ecmlen
) //cleanup old stats
355 ll_iter_remove_data(&it
);
359 //Old version, too slow to parse:
360 //fprintf(file, "%s rc %d caid %04hX prid %06X srvid %04hX time avg %d ms ecms %d last %ld fail %d len %02hX\n",
361 // rdr->label, s->rc, s->caid, s->prid,
362 // s->srvid, s->time_avg, s->ecm_count, s->last_received, s->fail_factor, s->ecmlen);
365 fprintf(file
, "%s,%d,%04hX,%06X,%04hX,%04hX,%d,%d,%ld,%d,%02hX\n",
366 rdr
->label
, s
->rc
, s
->caid
, s
->prid
,
367 s
->srvid
, (uint16_t)s
->chid
, s
->time_avg
, s
->ecm_count
, s
->last_received
.time
, s
->fail_factor
, s
->ecmlen
);
370 // if (count % 500 == 0) { //Saving stats is using too much cpu and causes high file load. so we need a break
371 // cs_readunlock(__func__, &rdr->lb_stat_lock);
373 // cs_readlock(__func__, &rdr->lb_stat_lock);
376 cs_writeunlock(__func__
, &rdr
->lb_stat_lock
);
378 rdr
->lb_stat_busy
= 0;
385 int64_t load_time
= comp_timeb(&te
, &ts
);
388 cs_log("loadbalancer: statistic saved %d records to %s in %"PRId64
" ms", count
, fname
, load_time
);
391 void save_stat_to_file(int32_t thread
)
395 { start_thread("save lb stats", (void *)&save_stat_to_file_thread
, NULL
, NULL
, 1, 1); }
397 { save_stat_to_file_thread(); }
401 * fail_factor is multiplied to the reopen_time. This function increases the fail_factor
403 static void inc_fail(READER_STAT
*s
)
405 if(s
->fail_factor
<= 0)
406 { s
->fail_factor
= 1; }
408 { s
->fail_factor
++; } // inc by one at the time
411 static READER_STAT
*get_add_stat(struct s_reader
*rdr
, STAT_QUERY
*q
)
413 if (rdr
->lb_stat_busy
)
418 rdr
->lb_stat
= ll_create("lb_stat");
419 cs_lock_create(__func__
, &rdr
->lb_stat_lock
, rdr
->label
, DEFAULT_LOCK_TIMEOUT
);
422 cs_writelock(__func__
, &rdr
->lb_stat_lock
);
424 READER_STAT
*s
= get_stat_lock(rdr
, q
, 0);
427 if(cs_malloc(&s
, sizeof(READER_STAT
)))
433 s
->ecmlen
= q
->ecmlen
;
434 s
->time_avg
= UNDEF_AVG_TIME
; //dummy placeholder
435 s
->rc
= E_FOUND
; //set to found--> do not change!
436 cs_ftime(&s
->last_received
);
439 ll_prepend(rdr
->lb_stat
, s
);
442 cs_writeunlock(__func__
, &rdr
->lb_stat_lock
);
447 static void housekeeping_stat(int32_t force
);
449 void readerinfofix_get_stat_query(ECM_REQUEST
*er
, STAT_QUERY
*q
)
451 get_stat_query(er
, q
);
454 void readerinfofix_inc_fail(READER_STAT
*s
)
459 READER_STAT
*readerinfofix_get_add_stat(struct s_reader
*rdr
, STAT_QUERY
*q
)
461 return get_add_stat(rdr
, q
);
464 static int32_t get_reopen_seconds(READER_STAT
*s
)
466 int32_t max
= (INT_MAX
/ cfg
.lb_reopen_seconds
);
467 if(max
> 9999) { max
= 9999; }
468 if(s
->fail_factor
> max
)
469 { s
->fail_factor
= max
; }
471 { return cfg
.lb_reopen_seconds
; }
472 return s
->fail_factor
* cfg
.lb_reopen_seconds
;
476 * Adds caid/prid/srvid/ecmlen to stat-list for reader ridx with time/rc
478 static void add_stat(struct s_reader
*rdr
, ECM_REQUEST
*er
, int32_t ecm_time
, int32_t rc
, uint8_t rcEx
)
480 //inc ecm_count if found, drop to 0 if not found:
497 // + = adds statistic values
498 // # = ignored because of duplicate values, temporary failures or softblocks
499 // - = causes loadbalancer to block this reader for this caid/prov/sid
502 if(!rdr
|| !er
|| !cfg
.lb_mode
|| !er
->ecmlen
|| !er
->client
|| rdr
->lb_stat_busy
)
505 struct s_client
*cl
= rdr
->client
;
506 if(!check_client(cl
))
510 //IGNORE stats for fallback reader with lb_force_fallback parameter
511 if(chk_is_fixed_fallback(rdr
, er
) && rdr
->lb_force_fallback
)
515 //IGNORE fails for ratelimit check
516 if(rc
== E_NOTFOUND
&& rcEx
== E2_RATELIMIT
)
519 if((D_LB
& cs_dblevel
))
521 char buf
[ECM_FMT_LEN
];
522 format_ecm(er
, buf
, ECM_FMT_LEN
);
523 cs_log_dbg(D_LB
, "loadbalancer: NOT adding stat (blocking) for reader %s because fails ratelimit checks!", rdr
->label
);
530 //IGNORE fails when reader has positive services defined in new lb_whitelist_services parameter! See ticket #3310,#3311
531 if(rc
>= E_NOTFOUND
&& has_lb_srvid(cl
, er
))
534 if((D_LB
& cs_dblevel
))
536 char buf
[ECM_FMT_LEN
];
537 format_ecm(er
, buf
, ECM_FMT_LEN
);
538 cs_log_dbg(D_LB
, "loadbalancer: NOT adding stat (blocking) for reader %s because has positive srvid: rc %d %s time %d ms",
539 rdr
->label
, rc
, buf
, ecm_time
);
546 //IGNORE fails for sleep CMD08
547 if(rc
== E_NOTFOUND
&& rdr
->client
->stopped
==2)
550 if((D_LB
& cs_dblevel
))
552 char buf
[ECM_FMT_LEN
];
553 format_ecm(er
, buf
, ECM_FMT_LEN
);
554 cs_log_dbg(D_LB
, "loadbalancer: NOT adding stat (no block) for reader %s because CMD08 sleep command!", rdr
->label
);
560 //IGNORE timeouts on local readers (they could be busy handling an emm or entitlement refresh)
561 if(rc
== E_TIMEOUT
&& !is_network_reader(rdr
))
564 if((D_LB
& cs_dblevel
))
566 cs_log_dbg(D_LB
, "loadbalancer: NOT adding stat (no block) for reader %s because timeout on local reader", rdr
->label
);
572 //IGNORE unhandled ecmresponses
573 if(rc
== E_UNHANDLED
)
576 if((D_LB
& cs_dblevel
))
578 cs_log_dbg(D_LB
, "loadbalancer: NOT adding stat (no block) for reader %s because unhandled reponse", rdr
->label
);
584 //ignore too old ecms
585 if((uint32_t)ecm_time
>= 3 * cfg
.ctimeout
)
588 if((uint32_t)ecm_time
>= cfg
.ctimeout
)
592 get_stat_query(er
, &q
);
594 s
= get_add_stat(rdr
, &q
);
600 cs_ftime(&s
->last_received
);
602 if(rc
== E_FOUND
) //found
611 if(s
->time_idx
>= LB_MAX_STAT_TIME
)
613 s
->time_stat
[s
->time_idx
] = ecm_time
;
616 //OLDEST READER now set by get best reader!
620 /* Assign a value to rdr->lb_usagelevel_ecmcount,
621 because no determined value was assigned before. */
622 if(rdr
->lb_usagelevel_ecmcount
< 0)
623 { rdr
->lb_usagelevel_ecmcount
= 0; }
625 rdr
->lb_usagelevel_ecmcount
++; /* ecm is found so counter should increase */
626 if((rdr
->lb_usagelevel_ecmcount
% cfg
.lb_min_ecmcount
) == 0) //update every MIN_ECM_COUNT usagelevel:
628 int64_t t
= comp_timeb(&now
, &rdr
->lb_usagelevel_time
) / 1000;
629 rdr
->lb_usagelevel
= cfg
.lb_min_ecmcount
* 1000 / (t
< 1 ? 1 : t
);
630 /* Reset of usagelevel time and counter */
631 rdr
->lb_usagelevel_time
= now
;
632 rdr
->lb_usagelevel_ecmcount
= 0;
636 else if(rc
== E_NOTFOUND
|| rc
== E_TIMEOUT
|| rc
== E_FAKE
) //not found / timeout /fake
641 else if(rc
== E_INVALID
) //invalid
648 if(rc
>= E_FOUND
&& (D_LB
& cs_dblevel
))
650 char buf
[ECM_FMT_LEN
];
651 format_ecm(er
, buf
, ECM_FMT_LEN
);
652 cs_log_dbg(D_LB
, "loadbalancer: not handled stat for reader %s: rc %d %s time %d ms",
653 rdr
->label
, rc
, buf
, ecm_time
);
659 housekeeping_stat(0);
662 if(D_LB
& cs_dblevel
)
664 char buf
[ECM_FMT_LEN
];
665 format_ecm(er
, buf
, ECM_FMT_LEN
);
666 cs_log_dbg(D_LB
, "loadbalancer: adding stat for reader %s: rc %d %s time %d ms fail %d",
667 rdr
->label
, rc
, buf
, ecm_time
, s
->fail_factor
);
674 if(stat_load_save
> cfg
.lb_save
)
675 { save_stat_to_file(1); }
680 int32_t clean_stat_by_rc(struct s_reader
*rdr
, int8_t rc
, int8_t inverse
)
683 if(rdr
&& rdr
->lb_stat
)
685 if (rdr
->lb_stat_busy
) return 0;
686 rdr
->lb_stat_busy
= 1;
687 cs_writelock(__func__
, &rdr
->lb_stat_lock
);
689 LL_ITER itr
= ll_iter_create(rdr
->lb_stat
);
690 while((s
= ll_iter_next(&itr
)))
692 if((!inverse
&& s
->rc
== rc
) || (inverse
&& s
->rc
!= rc
))
694 ll_iter_remove_data(&itr
);
698 cs_writeunlock(__func__
, &rdr
->lb_stat_lock
);
699 rdr
->lb_stat_busy
= 0;
704 int32_t clean_all_stats_by_rc(int8_t rc
, int8_t inverse
)
707 LL_ITER itr
= ll_iter_create(configured_readers
);
708 struct s_reader
*rdr
;
709 while((rdr
= ll_iter_next(&itr
)))
711 count
+= clean_stat_by_rc(rdr
, rc
, inverse
);
713 save_stat_to_file(0);
717 int32_t clean_stat_by_id(struct s_reader
*rdr
, uint16_t caid
, uint32_t prid
, uint16_t srvid
, uint16_t chid
, uint16_t ecmlen
)
720 if(rdr
&& rdr
->lb_stat
)
722 if (rdr
->lb_stat_busy
) return 0;
724 rdr
->lb_stat_busy
= 1;
725 cs_writelock(__func__
, &rdr
->lb_stat_lock
);
727 LL_ITER itr
= ll_iter_create(rdr
->lb_stat
);
728 while((s
= ll_iter_next(&itr
)))
730 if(s
->caid
== caid
&&
736 ll_iter_remove_data(&itr
);
738 break; // because the entry should unique we can left here
741 cs_writeunlock(__func__
, &rdr
->lb_stat_lock
);
742 rdr
->lb_stat_busy
= 0;
748 static int32_t has_ident(FTAB *ftab, ECM_REQUEST *er) {
750 if (!ftab || !ftab->filts)
755 for (j = 0; j < ftab->nfilts; j++) {
756 if (ftab->filts[j].caid) {
757 if (ftab->filts[j].caid==er->caid) { //caid matches!
758 int32_t nprids = ftab->filts[j].nprids;
759 if (!nprids) // No Provider ->Ok
762 for (k = 0; k < nprids; k++) {
763 uint32_t prid = ftab->filts[j].prids[k];
764 if (prid == er->prid) { //Provider matches
771 return 0; //No match!
774 static int32_t get_retrylimit(ECM_REQUEST
*er
)
776 return caidvaluetab_get_value(&cfg
.lb_retrylimittab
, er
->caid
, cfg
.lb_retrylimit
);
780 static int32_t get_nfb_readers(ECM_REQUEST
*er
)
783 int32_t nfb_readers
= er
->client
->account
->lb_nfb_readers
== -1 ? cfg
.lb_nfb_readers
: er
->client
->account
->lb_nfb_readers
;
785 if(nfb_readers
<= 0) { nfb_readers
= 1; }
791 static int32_t get_nbest_readers(ECM_REQUEST
*er
)
793 int32_t nbest_readers
= er
->client
->account
->lb_nbest_readers
== -1 ? cfg
.lb_nbest_readers
: er
->client
->account
->lb_nbest_readers
;
794 CAIDVALUETAB
*nbest_readers_tab
= er
->client
->account
->lb_nbest_readers_tab
.cvnum
== 0 ? &cfg
.lb_nbest_readers_tab
: &er
->client
->account
->lb_nbest_readers_tab
;
795 if(nbest_readers
<= 0) { nbest_readers
= 1; }
796 return caidvaluetab_get_value(nbest_readers_tab
, er
->caid
, nbest_readers
);
799 static void convert_to_beta_int(ECM_REQUEST
*er
, uint16_t caid_to
)
801 unsigned char md5tmp
[MD5_DIGEST_LENGTH
];
802 convert_to_beta(er
->client
, er
, caid_to
);
803 // update ecmd5 for store ECM in cache
804 memcpy(er
->ecmd5
, MD5(er
->ecm
+ 13, er
->ecmlen
- 13, md5tmp
), CS_ECMSTORESIZE
);
805 cacheex_update_hash(er
);
806 er
->btun
= 2; //marked as auto-betatunnel converted. Also for fixing recursive lock in get_cw
810 static void convert_to_nagra_int(ECM_REQUEST
*er
, uint16_t caid_to
)
812 unsigned char md5tmp
[MD5_DIGEST_LENGTH
];
813 convert_to_nagra(er
->client
, er
, caid_to
);
814 // update ecmd5 for store ECM in cache
815 memcpy(er
->ecmd5
, MD5(er
->ecm
+ 3, er
->ecmlen
- 3, md5tmp
), CS_ECMSTORESIZE
);
816 cacheex_update_hash(er
);
817 er
->btun
= 2; //marked as auto-betatunnel converted. Also for fixing recursive lock in get_cw
820 static int32_t lb_valid_btun(ECM_REQUEST
*er
, uint16_t caidto
)
824 struct s_reader
*rdr
;
826 get_stat_query(er
, &q
);
829 cs_readlock(__func__
, &readerlist_lock
);
830 for(rdr
= first_active_reader
; rdr
; rdr
= rdr
->next
)
832 if(rdr
->lb_stat
&& rdr
->client
)
834 s
= get_stat(rdr
, &q
);
835 if(s
&& s
->rc
== E_FOUND
)
837 cs_readunlock(__func__
, &readerlist_lock
);
842 cs_readunlock(__func__
, &readerlist_lock
);
846 static uint16_t __lb_get_betatunnel_caid_to(uint16_t caid
)
848 int32_t lbbm
= cfg
.lb_auto_betatunnel_mode
;
851 if(caid
== 0x1801) { return 0x1722; }
852 if(caid
== 0x1833) { return 0x1702; }
853 if(caid
== 0x1834) { return 0x1722; }
854 if(caid
== 0x1835) { return 0x1722; }
858 if(caid
== 0x1702) { return 0x1833; }
860 if(lbbm
== 1 || lbbm
== 4)
862 if(caid
== 0x1722) { return 0x1801; }
864 else if(lbbm
== 2 || lbbm
== 5)
866 if(caid
== 0x1722) { return 0x1834; }
868 else if(lbbm
== 3 || lbbm
== 6)
870 if(caid
== 0x1722) { return 0x1835; }
875 uint16_t lb_get_betatunnel_caid_to(ECM_REQUEST
*er
)
877 if(!cfg
.lb_auto_betatunnel
)
879 uint16_t caidto
= __lb_get_betatunnel_caid_to(er
->caid
);
880 if(lb_valid_btun(er
, caidto
))
886 void check_lb_auto_betatunnel_mode(ECM_REQUEST
*er
)
888 int32_t lbbm
= cfg
.lb_auto_betatunnel_mode
;
889 if(lbbm
== 1 || lbbm
== 4)
893 else if(lbbm
== 2 || lbbm
== 5)
897 else if(lbbm
== 3 || lbbm
== 6)
901 ////no other way to autodetect is 1801,1834 or 1835
904 uint16_t get_rdr_caid(struct s_reader
*rdr
)
906 if(is_network_reader(rdr
))
908 return 0; //reader caid is not real caid
916 static void reset_ecmcount_reader(READER_STAT
*s
, struct s_reader
*rdr
)
918 cs_readlock(__func__
, &rdr
->lb_stat_lock
);
919 if(rdr
->lb_stat
&& rdr
->client
)
926 cs_readunlock(__func__
, &rdr
->lb_stat_lock
);
929 static void reset_avgtime_reader(READER_STAT
*s
, struct s_reader
*rdr
)
931 cs_readlock(__func__
, &rdr
->lb_stat_lock
);
932 if(rdr
->lb_stat
&& rdr
->client
)
936 for(i
= 0; i
< LB_MAX_STAT_TIME
; i
++)
938 if(s
->time_stat
[i
] > 0) { s
->time_stat
[i
] = 0; }
940 s
->time_avg
= UNDEF_AVG_TIME
;
942 cs_readunlock(__func__
, &rdr
->lb_stat_lock
);
945 /* force_reopen=1 -> force opening of block readers
946 * force_reopen=0 -> no force opening of block readers, use reopen_seconds
948 static void try_open_blocked_readers(ECM_REQUEST
*er
, STAT_QUERY
*q
, int32_t *max_reopen
, int32_t *force_reopen
)
950 struct s_ecm_answer
*ea
;
952 struct s_reader
*rdr
;
955 for(ea
= er
->matching_rdr
; ea
; ea
= ea
->next
)
957 if((ea
->status
& READER_FALLBACK
) || (ea
->status
& READER_ACTIVE
)) { continue; }
959 s
= get_stat(rdr
, q
);
962 if(!cfg
.lb_reopen_invalid
&& s
->rc
== E_INVALID
){
963 cs_log_dbg(D_LB
, "loadbalancer: reader %s blocked because INVALID sent! It will be blocked until stats cleaned!", rdr
->label
);
967 //if force_reopen we must active the "valid" reader
968 if(s
->rc
!= E_FOUND
&& (*force_reopen
) && cfg
.lb_force_reopen_always
)
970 cs_log_dbg(D_LB
, "loadbalancer: force opening reader %s and reset fail_factor! --> ACTIVE", rdr
->label
);
971 ea
->status
|= READER_ACTIVE
;
976 //active readers reach get_reopen_seconds(s)
979 int64_t gone
= comp_timeb(&now
, &s
->last_received
);
980 int32_t reopenseconds
= get_reopen_seconds(s
);
981 if(s
->rc
!= E_FOUND
&& gone
> reopenseconds
*1000 )
985 cs_log_dbg(D_LB
, "loadbalancer: reader %s reaches %d seconds for reopening (fail_factor %d) --> ACTIVE", rdr
->label
, reopenseconds
, s
->fail_factor
);
986 ea
->status
|= READER_ACTIVE
;
991 cs_log_dbg(D_LB
, "loadbalancer: reader %s reaches %d seconds for reopening (fail_factor %d), but max_reopen reached!", rdr
->label
, reopenseconds
, s
->fail_factor
);
996 if(s
->rc
!= E_FOUND
) //for debug output
998 cs_log_dbg(D_LB
, "loadbalancer: reader %s blocked for %d seconds (fail_factor %d), retrying in %d seconds", rdr
->label
, get_reopen_seconds(s
), s
->fail_factor
, (uint
) (reopenseconds
- (gone
/1000)));
1002 if(s
->rc
== E_FOUND
) //for debug output
1003 { cs_log_dbg(D_LB
, "loadbalancer: reader %s \"e_found\" but not selected for lbvalue check", rdr
->label
); }
1011 * Gets best reader for caid/prid/srvid/ecmlen.
1012 * Best reader is evaluated by lowest avg time but only if ecm_count > cfg.lb_min_ecmcount (5)
1013 * Also the reader is asked if he is "available"
1014 * returns ridx when found or -1 when not found
1016 void stat_get_best_reader(ECM_REQUEST
*er
)
1018 if(!cfg
.lb_mode
|| cfg
.lb_mode
> 3)
1021 if(!er
->reader_avail
)
1024 struct s_reader
*rdr
;
1025 struct s_ecm_answer
*ea
;
1027 //preferred card forwarding (CCcam client):
1028 if(cccam_forward_origin_card(er
))
1032 get_stat_query(er
, &q
);
1035 //auto-betatunnel: The trick is: "let the loadbalancer decide"!
1036 if(cfg
.lb_auto_betatunnel
&& caid_is_nagra(er
->caid
) && er
->ecmlen
) //nagra
1038 uint16_t caid_to
= __lb_get_betatunnel_caid_to(er
->caid
);
1041 int8_t needs_stats_nagra
= 1, needs_stats_beta
= 1;
1043 //Clone query parameters for beta:
1044 STAT_QUERY qbeta
= q
;
1045 qbeta
.caid
= caid_to
;
1047 qbeta
.ecmlen
= er
->ecm
[2] + 3 + 10;
1049 int32_t time_nagra
= 0;
1050 int32_t time_beta
= 0;
1054 READER_STAT
*stat_nagra
= NULL
;
1055 READER_STAT
*stat_beta
= NULL
;
1057 //What is faster? nagra or beta?
1060 int8_t overall_valid
= 0;
1061 int8_t overall_nvalid
= 0;
1062 for(ea
= er
->matching_rdr
; ea
; ea
= ea
->next
)
1067 weight
= rdr
->lb_weight
;
1068 if(weight
<= 0) { weight
= 1; }
1071 //Check if betatunnel is allowed on this reader:
1072 int8_t valid
= chk_ctab(caid_to
, &rdr
->ctab
) //Check caid
1073 && chk_rfilter2(caid_to
, 0, rdr
) //Ident
1074 && chk_srvid_by_caid_prov_rdr(rdr
, caid_to
, 0) //Services
1075 && (!get_rdr_caid(rdr
) || chk_caid_rdr(rdr
, caid_to
)); //rdr-caid
1078 stat_beta
= get_stat(rdr
, &qbeta
);
1084 //Check if nagra is allowed on this reader:
1085 int8_t nvalid
= chk_ctab(er
->caid
, &rdr
->ctab
)//Check caid
1086 && chk_rfilter2(er
->caid
, 0, rdr
) //Ident
1087 && chk_srvid_by_caid_prov_rdr(rdr
, er
->caid
, 0) //Services
1088 && (!get_rdr_caid(rdr
) || chk_caid_rdr(rdr
, er
->caid
)); //rdr-caid
1091 stat_nagra
= get_stat(rdr
, &q
);
1095 //calculate nagra data:
1096 if(stat_nagra
&& stat_nagra
->rc
== E_FOUND
)
1098 ntime
= stat_nagra
->time_avg
* 100 / weight
;
1099 if(!time_nagra
|| ntime
< time_nagra
)
1100 { time_nagra
= ntime
; }
1103 //calculate beta data:
1104 if(stat_beta
&& stat_beta
->rc
== E_FOUND
)
1106 ntime
= stat_beta
->time_avg
* 100 / weight
;
1107 if(!time_beta
|| ntime
< time_beta
)
1108 { time_beta
= ntime
; }
1111 //Uncomplete reader evaluation, we need more stats!
1114 needs_stats_nagra
= 0;
1119 needs_stats_beta
= 0;
1122 cs_log_dbg(D_LB
, "loadbalancer-betatunnel valid %d, stat_nagra %d, stat_beta %d, (%04X,%04X)", valid
, isn
, isb
, get_rdr_caid(rdr
), caid_to
);
1125 if(!overall_valid
) //we have no valid betatunnel reader also we don't needs stats (converted)
1126 { needs_stats_beta
= 0; }
1128 if(!overall_nvalid
) //we have no valid reader also we don't needs stats (unconverted)
1129 { needs_stats_nagra
= 0; }
1131 if(cfg
.lb_auto_betatunnel_prefer_beta
&& time_beta
)
1133 time_beta
= time_beta
* cfg
.lb_auto_betatunnel_prefer_beta
/ 100;
1138 if(needs_stats_nagra
|| needs_stats_beta
)
1140 cs_log_dbg(D_LB
, "loadbalancer-betatunnel %04X:%04X (%d/%d) needs more statistics...", er
->caid
, caid_to
,
1141 needs_stats_nagra
, needs_stats_beta
);
1142 if(needs_stats_beta
) //try beta first
1145 convert_to_beta_int(er
, caid_to
);
1146 get_stat_query(er
, &q
);
1149 else if(time_beta
&& (!time_nagra
|| time_beta
<= time_nagra
))
1151 cs_log_dbg(D_LB
, "loadbalancer-betatunnel %04X:%04X selected beta: n%d ms > b%d ms", er
->caid
, caid_to
, time_nagra
, time_beta
);
1152 convert_to_beta_int(er
, caid_to
);
1153 get_stat_query(er
, &q
);
1157 cs_log_dbg(D_LB
, "loadbalancer-betatunnel %04X:%04X selected nagra: n%d ms < b%d ms", er
->caid
, caid_to
, time_nagra
, time_beta
);
1159 // else nagra is faster or no beta, so continue unmodified
1165 if(cfg
.lb_auto_betatunnel
&& (er
->caid
== 0x1702 || er
->caid
== 0x1722) && er
->ocaid
== 0x0000 && er
->ecmlen
) //beta
1167 uint16_t caid_to
= __lb_get_betatunnel_caid_to(er
->caid
);
1170 int8_t needs_stats_nagra
= 1, needs_stats_beta
= 1;
1172 //Clone query parameters for beta:
1173 STAT_QUERY qnagra
= q
;
1174 qnagra
.caid
= caid_to
;
1176 qnagra
.ecmlen
= er
->ecm
[2] - 7;
1178 int32_t time_nagra
= 0;
1179 int32_t time_beta
= 0;
1183 READER_STAT
*stat_nagra
= NULL
;
1184 READER_STAT
*stat_beta
= NULL
;
1185 //What is faster? nagra or beta?
1188 int8_t overall_valid
= 0;
1189 int8_t overall_bvalid
= 0;
1190 for(ea
= er
->matching_rdr
; ea
; ea
= ea
->next
)
1195 weight
= rdr
->lb_weight
;
1196 if(weight
<= 0) { weight
= 1; }
1200 //Check if reverse betatunnel is allowed on this reader:
1201 int8_t valid
= chk_ctab(caid_to
, &rdr
->ctab
)//, rdr->typ) //Check caid
1202 && chk_rfilter2(caid_to
, 0, rdr
) //Ident
1203 && chk_srvid_by_caid_prov_rdr(rdr
, caid_to
, 0) //Services
1204 && (!get_rdr_caid(rdr
) || chk_caid_rdr(rdr
, caid_to
)); //rdr-caid
1207 stat_nagra
= get_stat(rdr
, &qnagra
);
1211 //stat_nagra = NULL;
1213 //Check if beta is allowed on this reader:
1214 int8_t bvalid
= chk_ctab(er
->caid
, &rdr
->ctab
)//, rdr->typ) //Check caid
1215 && chk_rfilter2(er
->caid
, 0, rdr
) //Ident
1216 && chk_srvid_by_caid_prov_rdr(rdr
, er
->caid
, 0) //Services
1217 && (!get_rdr_caid(rdr
) || chk_caid_rdr(rdr
, er
->caid
)); //rdr-caid
1220 stat_beta
= get_stat(rdr
, &q
);
1224 //calculate nagra data:
1225 if(stat_nagra
&& stat_nagra
->rc
== E_FOUND
)
1227 avg_time
= stat_nagra
->time_avg
* 100 / weight
;
1228 if(!time_nagra
|| avg_time
< time_nagra
)
1229 { time_nagra
= avg_time
; }
1232 //calculate beta data:
1233 if(stat_beta
&& stat_beta
->rc
== E_FOUND
)
1235 avg_time
= stat_beta
->time_avg
* 100 / weight
;
1236 if(!time_beta
|| avg_time
< time_beta
)
1237 { time_beta
= avg_time
; }
1240 //Uncomplete reader evaluation, we need more stats!
1243 needs_stats_beta
= 0;
1248 needs_stats_nagra
= 0;
1251 cs_log_dbg(D_LB
, "loadbalancer-betatunnel valid %d, stat_beta %d, stat_nagra %d, (%04X,%04X)", valid
, isb
, isn
, get_rdr_caid(rdr
), caid_to
);
1254 if(!overall_valid
) //we have no valid reverse betatunnel reader also we don't needs stats (converted)
1255 { needs_stats_nagra
= 0; }
1257 if(!overall_bvalid
) //we have no valid reader also we don't needs stats (unconverted)
1258 { needs_stats_beta
= 0; }
1260 if(cfg
.lb_auto_betatunnel_prefer_beta
&& time_beta
)
1262 time_beta
= time_beta
* cfg
.lb_auto_betatunnel_prefer_beta
/ 100;
1267 //if we needs stats, we send 2 ecm requests: 18xx and 17xx:
1268 if(needs_stats_nagra
|| needs_stats_beta
)
1270 cs_log_dbg(D_LB
, "loadbalancer-betatunnel %04X:%04X (%d/%d) needs more statistics...", er
->caid
, caid_to
,
1271 needs_stats_beta
, needs_stats_nagra
);
1272 if(needs_stats_nagra
) // try nagra frist
1275 convert_to_nagra_int(er
, caid_to
);
1276 get_stat_query(er
, &q
);
1280 else if(time_nagra
&& (!time_beta
|| time_nagra
<= time_beta
))
1282 cs_log_dbg(D_LB
, "loadbalancer-betatunnel %04X:%04X selected nagra: b%d ms > n%d ms", er
->caid
, caid_to
, time_beta
, time_nagra
);
1283 convert_to_nagra_int(er
, caid_to
);
1284 get_stat_query(er
, &q
);
1288 cs_log_dbg(D_LB
, "loadbalancer-betatunnel %04X:%04X selected beta: b%d ms < n%d ms", er
->caid
, caid_to
, time_beta
, time_nagra
);
1294 if(cfg
.lb_auto_betatunnel
&& chk_is_betatunnel_caid(er
->caid
))
1296 //check again is caid valied to reader
1297 //with both caid on local readers or with proxy
1298 //(both caid will setup to reader for make tunnel caid in share (ccc) visible)
1299 //make sure dosn't send a beta ecm to nagra reader (or reverse)
1300 struct s_ecm_answer
*prv
= NULL
;
1301 for(ea
= er
->matching_rdr
; ea
; ea
= ea
->next
)
1304 if(is_network_reader(rdr
)) //reader caid is not real caid
1307 continue; // proxy can convert or reject
1309 cs_log_dbg(D_LB
, "check again caid %04X on reader %s", er
->caid
, rdr
->label
);
1310 if(!get_rdr_caid(ea
->reader
) || chk_caid_rdr(ea
->reader
, er
->caid
))
1316 if(!chk_is_fixed_fallback(rdr
, er
)) { er
->reader_avail
--; }
1317 cs_log_dbg(D_LB
, "caid %04X not found in caidlist, reader %s removed from request reader list", er
->caid
, rdr
->label
);
1320 prv
->next
= ea
->next
;
1323 { er
->matching_rdr
= ea
->next
; }
1326 if(!er
->reader_avail
)
1330 struct timeb check_time
;
1331 cs_ftime(&check_time
);
1332 int64_t current
= -1;
1333 READER_STAT
*s
= NULL
;
1334 int32_t retrylimit
= get_retrylimit(er
);
1335 int32_t nlocal_readers
= 0;
1337 int32_t nbest_readers
= get_nbest_readers(er
); // Number of NON fallback readers ecm requests go (minimum 1)
1338 int32_t nfb_readers
= get_nfb_readers(er
); // Number of fallback readers ecm requests go (minimum 1)
1339 int32_t nreaders
= cfg
.lb_max_readers
; // lb_max_readers is limit lb uses while learning
1342 if(!nreaders
) // if is configured zero -> replace it by -1 (default means unlimited!)
1344 else if(nreaders
<= nbest_readers
)
1345 { nreaders
= nbest_readers
+ 1; } //nreaders must cover nbest more 1 reader for try to unblock/add stats
1347 int32_t reader_active
= 0;
1348 int32_t max_reopen
= nreaders
- nbest_readers
; //if nreaders=-1, we try to reopen all readers
1352 if(cs_dblevel
& D_LB
)
1354 //loadbalancer debug output:
1361 for(ea
= er
->matching_rdr
; ea
; ea
= ea
->next
)
1365 if(nr
> 5) { continue; }
1367 if(!(ea
->status
& READER_FALLBACK
))
1368 { n
= snprintf(rptr
, l
, "%s%s%s ", ea
->reader
->label
, (ea
->status
& READER_CACHEEX
) ? "*" : "", (ea
->status
& READER_LOCAL
) ? "L" : ""); }
1370 { n
= snprintf(rptr
, l
, "[%s%s%s] ", ea
->reader
->label
, (ea
->status
& READER_CACHEEX
) ? "*" : "", (ea
->status
& READER_LOCAL
) ? "L" : ""); }
1376 { snprintf(rptr
, l
, "...(%d more)", nr
- 5); }
1378 char ecmbuf
[ECM_FMT_LEN
];
1379 format_ecm(er
, ecmbuf
, ECM_FMT_LEN
);
1381 cs_log_dbg(D_LB
, "loadbalancer: client %s for %s: n=%d valid readers: %s",
1382 username(er
->client
), ecmbuf
, nr
, buf
);
1387 //Deactive all matching readers and set ea->value = 0;
1388 for(ea
= er
->matching_rdr
; ea
; ea
= ea
->next
)
1390 ea
->status
&= ~(READER_ACTIVE
| READER_FALLBACK
);
1394 cs_log_dbg(D_LB
, "loadbalancer: --------------------------------------------");
1395 if(max_reopen
< 1) { cs_log_dbg(D_LB
, "loadbalancer: mode %d, nbest %d, nfb %d, max_reopen ALL, retrylimit %d ms", cfg
.lb_mode
, nbest_readers
, nfb_readers
, retrylimit
); }
1396 else { cs_log_dbg(D_LB
, "loadbalancer: mode %d, nbest %d, nfb %d, max_reopen %d, retrylimit %d ms", cfg
.lb_mode
, nbest_readers
, nfb_readers
, max_reopen
, retrylimit
); }
1399 //Here evaluate lbvalue for readers with valid statistics
1400 for(ea
= er
->matching_rdr
; ea
; ea
= ea
->next
)
1404 s
= get_stat(rdr
, &q
);
1407 int32_t weight
= rdr
->lb_weight
<= 0 ? 100 : rdr
->lb_weight
;
1408 //struct s_client *cl = rdr->client;
1410 if(s
&& s
->rc
== E_FOUND
1411 && s
->ecm_count
>= cfg
.lb_min_ecmcount
1412 && (s
->ecm_count
<= cfg
.lb_max_ecmcount
|| (retrylimit
&& s
->time_avg
<= retrylimit
))
1416 //Reader can decode this service (rc==0) and has lb_min_ecmcount ecms:
1417 if(er
->preferlocalcards
&& (ea
->status
& READER_LOCAL
))
1418 { nlocal_readers
++; } //Prefer local readers!
1422 case LB_FASTEST_READER_FIRST
:
1423 current
= s
->time_avg
* 100 / weight
;
1426 case LB_OLDEST_READER_FIRST
:
1427 if(!rdr
->lb_last
.time
)
1428 { rdr
->lb_last
= check_time
; }
1430 //current is negative here!
1431 current
= comp_timeb(&rdr
->lb_last
, &check_time
);
1433 current
= current
* weight
/ 100;
1435 if(!current
) { current
= -1; }
1440 if(s
->time_avg
> retrylimit
){ //set lowest value for reader with time-avg>retrylimit
1441 current
= s
->time_avg
; //in this way, it will choose best time-avg reader among the worst ones
1443 current
= current
- 1; //so when all have same current, it prioritizes the one with s->time_avg<=retrylimit! This avoid a loop!
1449 case LB_LOWEST_USAGELEVEL
:
1450 current
= rdr
->lb_usagelevel
* 100 / weight
;
1455 if(s
->time_avg
> retrylimit
)
1456 { current
= 1000; } //set lowest value for reader with time-avg>retrylimit
1458 { current
= current
- 1; } //so when all reaches retrylimit (all have lb_value=1000) or all have same current, it prioritizes the one with s->time_avg<=retrylimit! This avoid a loop!
1464 if(cfg
.lb_mode
!= LB_OLDEST_READER_FIRST
) //Adjust selection to reader load:
1466 /* if (rdr->ph.c_available && !rdr->ph.c_available(rdr, AVAIL_CHECK_LOADBALANCE, er)) {
1470 if (cl && cl->pending)
1471 current=current*cl->pending;
1478 cs_log_dbg(D_LB
, "loadbalancer: reader %s lbvalue = %d (time-avg %d)", rdr
->label
, (int) llabs(current
), s
->time_avg
);
1480 #if defined(WEBIF) || defined(LCDSUPPORT)
1481 rdr
->lbvalue
= llabs(current
);
1484 ea
->value
= current
;
1485 ea
->time
= s
->time_avg
;
1489 //check for local readers
1490 if(nlocal_readers
> nbest_readers
) //if we have local readers, we prefer them!
1492 nlocal_readers
= nbest_readers
;
1496 { nbest_readers
= nbest_readers
- nlocal_readers
; }
1499 struct s_reader
*best_rdr
= NULL
;
1500 struct s_reader
*best_rdri
= NULL
;
1501 int32_t best_time
= 0;
1503 //Here choose nbest readers. We evaluate only readers with valid stats (they have ea->value>0, calculated above)
1506 struct s_ecm_answer
*best
= NULL
;
1508 for(ea
= er
->matching_rdr
; ea
; ea
= ea
->next
)
1510 if(nlocal_readers
&& !(ea
->status
& READER_LOCAL
))
1513 if(ea
->value
&& (!best
|| ea
->value
< best
->value
))
1519 best_rdri
= best
->reader
;
1522 best_rdr
= best_rdri
;
1523 best_time
= best
->time
;
1526 if(nlocal_readers
) //primary readers, local
1530 best
->status
|= READER_ACTIVE
;
1532 cs_log_dbg(D_LB
, "loadbalancer: reader %s --> ACTIVE", best_rdri
->label
);
1534 else if(nbest_readers
) //primary readers, other
1538 best
->status
|= READER_ACTIVE
;
1540 cs_log_dbg(D_LB
, "loadbalancer: reader %s --> ACTIVE", best_rdri
->label
);
1547 /* Here choose nfb_readers
1548 * Select fallbacks reader until nfb_readers reached using this priority:
1549 * 1. forced (lb_force_fallback=1) fixed fallback
1550 * 2. "normal" fixed fallback
1551 * 3. best ea->value remaining reader;
1553 //check for fixed fallbacks
1554 int32_t n_fixed_fb
= chk_has_fixed_fallback(er
);
1557 //check before for lb_force_fallback=1 readers
1558 for(ea
= er
->matching_rdr
; ea
&& nfb_readers
; ea
= ea
->next
)
1561 if(chk_is_fixed_fallback(rdr
, er
) && rdr
->lb_force_fallback
&& !(ea
->status
& READER_ACTIVE
)){
1563 ea
->status
|= (READER_ACTIVE
| READER_FALLBACK
);
1564 cs_log_dbg(D_LB
, "loadbalancer: reader %s --> FALLBACK (FIXED with force)", rdr
->label
);
1568 //check for "normal" fixed fallback with valid stats
1569 for(ea
= er
->matching_rdr
; ea
&& nfb_readers
; ea
= ea
->next
)
1572 if(chk_is_fixed_fallback(rdr
, er
) && !rdr
->lb_force_fallback
&& !(ea
->status
& READER_ACTIVE
)){
1574 s
= get_stat(rdr
, &q
);
1575 if(s
&& s
->rc
== E_FOUND
1576 && s
->ecm_count
>= cfg
.lb_min_ecmcount
1577 && (s
->ecm_count
<= cfg
.lb_max_ecmcount
|| (retrylimit
&& s
->time_avg
<= retrylimit
))
1581 ea
->status
|= (READER_ACTIVE
| READER_FALLBACK
);
1582 cs_log_dbg(D_LB
, "loadbalancer: reader %s --> FALLBACK (FIXED)", rdr
->label
);
1588 //check for remaining best ea->value readers as fallbacks
1591 struct s_ecm_answer
*best
= NULL
;
1593 for(ea
= er
->matching_rdr
; ea
; ea
= ea
->next
)
1595 if((ea
->status
& READER_ACTIVE
))
1598 if(ea
->value
&& (!best
|| ea
->value
< best
->value
))
1605 best
->status
|= (READER_ACTIVE
| READER_FALLBACK
);
1607 cs_log_dbg(D_LB
, "loadbalancer: reader %s --> FALLBACK", best
->reader
->label
);
1609 //end fallback readers
1613 //ACTIVE readers with no stats, or with no lb_min_ecmcount, or lb_max_ecmcount reached --> NO use max_reopen for these readers, always open!
1614 for(ea
= er
->matching_rdr
; ea
; ea
= ea
->next
)
1617 s
= get_stat(rdr
, &q
);
1621 //if cacheex reader, always active and no stats
1622 if(rdr
->cacheex
.mode
== 1)
1624 ea
->status
|= READER_ACTIVE
;
1629 //ignore fixed fallback with lb_force_fallback=1: no need stats, always used as fallaback!
1630 if(chk_is_fixed_fallback(rdr
, er
) && rdr
->lb_force_fallback
)
1633 //active readers with no stats
1636 cs_log_dbg(D_LB
, "loadbalancer: reader %s need starting statistics --> ACTIVE", rdr
->label
);
1637 ea
->status
|= READER_ACTIVE
;
1642 //active readers with no lb_min_ecmcount reached
1643 if(s
->rc
== E_FOUND
&& s
->ecm_count
< cfg
.lb_min_ecmcount
)
1645 cs_log_dbg(D_LB
, "loadbalancer: reader %s needs to reach lb_min_ecmcount(%d), now %d --> ACTIVE", rdr
->label
, cfg
.lb_min_ecmcount
, s
->ecm_count
);
1646 ea
->status
|= READER_ACTIVE
;
1651 //reset stats and active readers reach cfg.lb_max_ecmcount and time_avg > retrylimit.
1652 if(s
->rc
== E_FOUND
&& s
->ecm_count
> cfg
.lb_max_ecmcount
&& (!retrylimit
|| s
->time_avg
> retrylimit
))
1654 cs_log_dbg(D_LB
, "loadbalancer: reader %s reaches max ecms (%d), resetting statistics --> ACTIVE", rdr
->label
, cfg
.lb_max_ecmcount
);
1655 reset_ecmcount_reader(s
, rdr
); //ecm_count=0
1656 reset_avgtime_reader(s
, rdr
); //time_avg=0
1657 ea
->status
|= READER_ACTIVE
;
1664 int64_t gone
= comp_timeb(&now
, &s
->last_received
);
1665 //reset avg-time and active reader with s->last_received older than 5 min and avg-time>retrylimit
1666 if(retrylimit
&& s
->rc
== E_FOUND
&& (gone
>= 300*1000) && s
->time_avg
> retrylimit
)
1668 cs_log_dbg(D_LB
, "loadbalancer: reader %s has time-avg>retrylimit and last received older than 5 minutes, resetting avg-time --> ACTIVE", rdr
->label
);
1669 reset_avgtime_reader(s
, rdr
); //time_avg=0
1670 ea
->status
&= ~(READER_ACTIVE
| READER_FALLBACK
); //It could be activated as fallback above because has lb_vlaue>0, so remove fallback state!
1671 ea
->status
|= READER_ACTIVE
;
1678 int32_t force_reopen
= 0;
1681 //no reader active --> force to reopen matching readers
1682 if(reader_active
== 0)
1684 cs_log_dbg(D_LB
, "loadbalancer: NO VALID MATCHING READER FOUND!");
1691 * check for lbretrylimit!
1693 * if best_time > retrylimit we need to reset avg times of all computed above matching readers, so we can re-evaluated lbvalue!
1694 * More, we force open blocked reader!
1696 int32_t retrylimit_reached
= best_time
&& best_time
> retrylimit
;
1697 if(retrylimit_reached
)
1699 cs_log_dbg(D_LB
, "loadbalancer: best reader %s (avg_time %d ms) reaches RETRYLIMIT (%d ms), resetting avg times and ACTIVE all (valid and blocked) matching readers!", best_rdr
->label
, best_time
, retrylimit
);
1700 for(ea
= er
->matching_rdr
; ea
; ea
= ea
->next
)
1704 if(rdr
->cacheex
.mode
== 1) { continue; }
1706 s
= get_stat(rdr
, &q
);
1708 //reset avg time and ACTIVE all valid lbvalue readers
1709 if(s
&& s
->rc
== E_FOUND
1710 && s
->ecm_count
>= cfg
.lb_min_ecmcount
1711 && (s
->ecm_count
<= cfg
.lb_max_ecmcount
|| s
->time_avg
<= retrylimit
)
1714 if((ea
->status
& READER_FALLBACK
)) { cs_log_dbg(D_LB
, "loadbalancer: reader %s selected as FALLBACK --> ACTIVE", rdr
->label
); }
1715 else if(!(ea
->status
& READER_ACTIVE
)) { cs_log_dbg(D_LB
, "loadbalancer: reader %s --> ACTIVE", rdr
->label
); }
1716 ea
->status
&= ~(READER_ACTIVE
| READER_FALLBACK
); //remove active and fallback
1717 ea
->status
|= READER_ACTIVE
; //add active
1718 reset_avgtime_reader(s
, rdr
);
1721 //reset avg time all blocked "valid" readers. We active them by force_reopen=1
1722 if(s
&& s
->rc
!= E_FOUND
)
1724 reset_avgtime_reader(s
, rdr
);
1728 force_reopen
= 1; //force reopen blocked readers
1733 //try to reopen max_reopen blocked readers (readers with last ecm not "e_found"); if force_reopen=1, force reopen valid blocked readers!
1734 try_open_blocked_readers(er
, &q
, &max_reopen
, &force_reopen
);
1737 cs_log_dbg(D_LB
, "loadbalancer: --------------------------------------------");
1742 if(cs_dblevel
& D_LB
)
1744 //loadbalancer debug output:
1752 for(ea
= er
->matching_rdr
; ea
; ea
= ea
->next
)
1754 if(!(ea
->status
& READER_ACTIVE
))
1759 if(nr
> 5) { continue; }
1761 if(!(ea
->status
& READER_FALLBACK
))
1762 { n
= snprintf(rptr
, l
, "%s%s%s ", ea
->reader
->label
, (ea
->status
& READER_CACHEEX
) ? "*" : "", (ea
->status
& READER_LOCAL
) ? "L" : ""); }
1764 { n
= snprintf(rptr
, l
, "[%s%s%s] ", ea
->reader
->label
, (ea
->status
& READER_CACHEEX
) ? "*" : "", (ea
->status
& READER_LOCAL
) ? "L" : ""); }
1770 { snprintf(rptr
, l
, "...(%d more)", nr
- 5); }
1772 char ecmbuf
[ECM_FMT_LEN
];
1773 format_ecm(er
, ecmbuf
, ECM_FMT_LEN
);
1775 cs_log_dbg(D_LB
, "loadbalancer: client %s for %s: n=%d selected readers: %s",
1776 username(er
->client
), ecmbuf
, nr
, buf
);
1785 * clears statistic of reader ridx.
1787 void clear_reader_stat(struct s_reader
*rdr
)
1792 ll_clear_data(rdr
->lb_stat
);
1795 void clear_all_stat(void)
1797 struct s_reader
*rdr
;
1798 LL_ITER itr
= ll_iter_create(configured_readers
);
1799 while((rdr
= ll_iter_next(&itr
)))
1801 clear_reader_stat(rdr
);
1805 static void housekeeping_stat_thread(void)
1809 int32_t cleanup_timeout
= cfg
.lb_stat_cleanup
* 60 * 60 * 1000;
1810 int32_t cleaned
= 0;
1811 struct s_reader
*rdr
;
1812 set_thread_name(__func__
);
1813 LL_ITER itr
= ll_iter_create(configured_readers
);
1814 cs_readlock(__func__
, &readerlist_lock
); //this avoids cleaning a reading during writing
1815 while((rdr
= ll_iter_next(&itr
)))
1819 rdr
->lb_stat_busy
= 1;
1820 cs_writelock(__func__
, &rdr
->lb_stat_lock
);
1821 LL_ITER it
= ll_iter_create(rdr
->lb_stat
);
1823 while((s
= ll_iter_next(&it
)))
1826 int64_t gone
= comp_timeb(&now
, &s
->last_received
);
1827 if(gone
> cleanup_timeout
)
1829 ll_iter_remove_data(&it
);
1833 cs_writeunlock(__func__
, &rdr
->lb_stat_lock
);
1834 rdr
->lb_stat_busy
= 0;
1837 cs_readunlock(__func__
, &readerlist_lock
);
1838 cs_log_dbg(D_LB
, "loadbalancer cleanup: removed %d entries", cleaned
);
1841 static void housekeeping_stat(int32_t force
)
1845 int64_t gone
= comp_timeb(&now
, &last_housekeeping
);
1846 if(!force
&& (gone
< 60*60*1000)) //only clean once in an hour
1849 last_housekeeping
= now
;
1850 start_thread("housekeeping lb stats", (void *)&housekeeping_stat_thread
, NULL
, NULL
, 1, 1);
1853 static int compare_stat(READER_STAT
**ps1
, READER_STAT
**ps2
)
1855 READER_STAT
*s1
= (*ps1
), *s2
= (*ps2
);
1856 int64_t res
= s1
->rc
- s2
->rc
;
1857 if(res
) { return res
; }
1858 res
= s1
->caid
- s2
->caid
;
1859 if(res
) { return res
; }
1860 res
= s1
->prid
- s2
->prid
;
1861 if(res
) { return res
; }
1862 res
= s1
->srvid
- s2
->srvid
;
1863 if(res
) { return res
; }
1864 res
= s1
->chid
- s2
->chid
;
1865 if(res
) { return res
; }
1866 res
= s1
->ecmlen
- s2
->ecmlen
;
1867 if(res
) { return res
; }
1868 res
= comp_timeb(&s1
->last_received
, &s2
->last_received
);
1872 static int compare_stat_r(READER_STAT
**ps1
, READER_STAT
**ps2
)
1874 return -compare_stat(ps1
, ps2
);
1877 READER_STAT
**get_sorted_stat_copy(struct s_reader
*rdr
, int32_t reverse
, int32_t *size
)
1880 { return (READER_STAT
**)ll_sort(rdr
->lb_stat
, compare_stat_r
, size
); }
1882 { return (READER_STAT
**)ll_sort(rdr
->lb_stat
, compare_stat
, size
); }
1885 static int8_t stat_in_ecmlen(struct s_reader
*rdr
, READER_STAT
*s
)
1888 for (i
= 0; i
< rdr
->ecm_whitelist
.ewnum
; i
++)
1890 ECM_WHITELIST_DATA
*d
= &rdr
->ecm_whitelist
.ewdata
[i
];
1891 if ((d
->caid
== 0 || d
->caid
== s
->caid
) && (d
->ident
== 0 || d
->ident
== s
->prid
) && (d
->len
== s
->ecmlen
))
1897 static int8_t add_to_ecmlen(struct s_reader
*rdr
, READER_STAT
*s
)
1900 for (i
= 0; i
< rdr
->ecm_whitelist
.ewnum
; i
++)
1902 ECM_WHITELIST_DATA
*d
= &rdr
->ecm_whitelist
.ewdata
[i
];
1903 if ((d
->caid
== s
->caid
) && (d
->ident
== s
->prid
) && (d
->len
== s
->ecmlen
))
1906 ECM_WHITELIST_DATA d
= { .caid
= s
->caid
, .ident
= s
->prid
, .len
= s
->ecmlen
};
1907 ecm_whitelist_add(&rdr
->ecm_whitelist
, &d
);
1911 void update_ecmlen_from_stat(struct s_reader
*rdr
)
1913 if(!rdr
|| !rdr
->lb_stat
)
1916 cs_readlock(__func__
, &rdr
->lb_stat_lock
);
1917 LL_ITER it
= ll_iter_create(rdr
->lb_stat
);
1919 while((s
= ll_iter_next(&it
)))
1921 if(s
->rc
== E_FOUND
)
1923 if(!stat_in_ecmlen(rdr
, s
))
1924 { add_to_ecmlen(rdr
, s
); }
1927 cs_readunlock(__func__
, &rdr
->lb_stat_lock
);
1931 * mark as last reader after checked for cache requests:
1933 void lb_mark_last_reader(ECM_REQUEST
*er
)
1935 //OLDEST_READER: set lb_last
1936 struct s_ecm_answer
*ea
;
1937 for(ea
= er
->matching_rdr
; ea
; ea
= ea
->next
)
1939 if((ea
->status
& (READER_ACTIVE
| READER_FALLBACK
)) == READER_ACTIVE
)
1940 { cs_ftime(&ea
->reader
->lb_last
); }
1946 * Automatic timeout feature depending on statistik values
1948 static uint32_t __lb_auto_timeout(ECM_REQUEST
*er
, uint32_t ctimeout
)
1951 READER_STAT
*s
= NULL
;
1953 struct s_reader
*rdr
= NULL
;
1954 struct s_ecm_answer
*ea
;
1956 for(ea
= er
->matching_rdr
; ea
; ea
= ea
->next
)
1958 if((ea
->status
& (READER_ACTIVE
| READER_FALLBACK
)) == READER_ACTIVE
)
1961 get_stat_query(er
, &q
);
1962 s
= get_stat(rdr
, &q
);
1966 if(!s
) { return ctimeout
; }
1969 if(s
->rc
== E_TIMEOUT
)
1970 { t
= ctimeout
/ 2; } //timeout known, early timeout!
1973 if(s
->ecm_count
< cfg
.lb_min_ecmcount
) { return ctimeout
; }
1975 t
= s
->time_avg
* (100 + cfg
.lb_auto_timeout_p
) / 100;
1976 if((int32_t)(t
- s
->time_avg
) < cfg
.lb_auto_timeout_t
) { t
= s
->time_avg
+ cfg
.lb_auto_timeout_t
; }
1978 if(t
> ctimeout
) { t
= ctimeout
; }
1980 if(D_TRACE
& cs_dblevel
)
1982 char buf
[ECM_FMT_LEN
];
1983 format_ecm(er
, buf
, ECM_FMT_LEN
);
1984 cs_log_dbg(D_TRACE
, "auto-timeout for %s %s set rdr %s to %d", username(er
->client
), buf
, rdr
->label
, t
);
1990 uint32_t lb_auto_timeout(ECM_REQUEST
*er
, uint32_t timeout
)
1992 if(cfg
.lb_auto_timeout
)
1993 return __lb_auto_timeout(er
, timeout
);
1997 bool lb_check_auto_betatunnel(ECM_REQUEST
*er
, struct s_reader
*rdr
)
1999 if(!cfg
.lb_auto_betatunnel
)
2003 uint16_t caid
= __lb_get_betatunnel_caid_to(er
->caid
);
2006 uint16_t save_caid
= er
->caid
;
2008 match
= matching_reader(er
, rdr
); //matching
2009 er
->caid
= save_caid
;
2015 * search for same ecm hash with same readers
2017 static struct ecm_request_t
*check_same_ecm(ECM_REQUEST
*er
)
2019 struct ecm_request_t
*ecm
;
2021 struct s_ecm_answer
*ea_ecm
= NULL
, *ea_er
= NULL
;
2025 cs_readlock(__func__
, &ecmcache_lock
);
2026 for(ecm
= ecmcwcache
; ecm
; ecm
= ecm
->next
)
2028 timeout
= time(NULL
) - ((cfg
.ctimeout
+ 500) / 1000);
2030 if(ecm
->tps
.time
<= timeout
)
2033 if(ecm
== er
) { continue; }
2035 if(er
->caid
!= ecm
->caid
|| memcmp(ecm
->ecmd5
, er
->ecmd5
, CS_ECMSTORESIZE
))
2038 if(!er
->readers
|| !ecm
->readers
|| er
->readers
!= ecm
->readers
)
2041 ea_ecm
= ecm
->matching_rdr
;
2042 ea_er
= er
->matching_rdr
;
2045 while(rdrs
&& ea_ecm
&& ea_er
)
2047 if(ea_ecm
->reader
!= ea_er
->reader
)
2049 ea_ecm
= ea_ecm
->next
;
2050 ea_er
= ea_er
->next
;
2056 cs_readunlock(__func__
, &ecmcache_lock
);
2060 cs_readunlock(__func__
, &ecmcache_lock
);
2061 return NULL
; // nothing found so return null
2064 static void use_same_readers(ECM_REQUEST
*er_new
, ECM_REQUEST
*er_cache
)
2066 struct s_ecm_answer
*ea_new
= er_new
->matching_rdr
;
2067 struct s_ecm_answer
*ea_cache
= er_cache
->matching_rdr
;
2068 uint8_t rdrs
= er_new
->readers
;
2071 ea_new
->status
&= ~(READER_ACTIVE
| READER_FALLBACK
);
2072 if((ea_cache
->status
& READER_ACTIVE
))
2074 if(!(ea_cache
->status
& READER_FALLBACK
))
2076 ea_new
->status
|= READER_ACTIVE
;
2080 ea_new
->status
|= (READER_ACTIVE
| READER_FALLBACK
);
2084 ea_new
= ea_new
->next
;
2085 ea_cache
= ea_cache
->next
;
2090 void lb_set_best_reader(ECM_REQUEST
*er
)
2094 // cache2 is handled by readers queue, so, if a same ecm hash with same readers, use these same readers to get cache2 from them! Not ask other readers!
2095 struct ecm_request_t
*ecm_eq
= NULL
;
2096 ecm_eq
= check_same_ecm(er
);
2099 // set all readers used by ecm_eq, so we get cache2 from them!
2100 use_same_readers(er
, ecm_eq
);
2101 cs_log_dbg(D_LB
, "{client %s, caid %04X, prid %06X, srvid %04X} [get_cw] found same ecm with same readers from client %s, use them!", (check_client(er
->client
) ? er
->client
->account
->usr
: "-"), er
->caid
, er
->prid
, er
->srvid
, (check_client(ecm_eq
->client
) ? ecm_eq
->client
->account
->usr
: "-"));
2103 // FILTER readers by loadbalancing
2104 stat_get_best_reader(er
);
2108 void lb_update_last(struct s_ecm_answer
*ea_er
, struct s_reader
*reader
)
2110 // for lb oldest reader mode - not use for fallback readers
2111 if (!(ea_er
->status
& READER_FALLBACK
))
2112 cs_ftime(&reader
->lb_last
);
2116 void send_reader_stat(struct s_reader
*rdr
, ECM_REQUEST
*er
, struct s_ecm_answer
*ea
, int8_t rc
)
2118 if(rc
>= E_99
|| cacheex_reader(rdr
))
2121 int32_t ecm_time
= cfg
.ctimeout
;
2122 if(ea
->ecm_time
&& ea
->rc
<= E_NOTFOUND
)
2123 { ecm_time
= ea
->ecm_time
; }
2125 add_stat(rdr
, er
, ecm_time
, rc
, ea
->rcEx
);
2128 void stat_finish(void)
2130 if(cfg
.lb_mode
&& cfg
.lb_save
)
2132 save_stat_to_file(0);
2134 { cs_log("stats saved to file %s", cfg
.lb_savepath
); }
2135 cfg
.lb_save
= 0; //this is for avoiding duplicate saves