1 #define MODULE_LOG_PREFIX "config"
3 //FIXME Not checked on threadsafety yet; after checking please remove this line
7 #include "oscam-conf.h"
8 #include "oscam-conf-chk.h"
9 #include "oscam-config.h"
10 #include "oscam-files.h"
11 #include "oscam-garbage.h"
12 #include "oscam-lock.h"
13 #include "oscam-string.h"
14 #include "oscam-time.h"
16 #define cs_srid "oscam.srvid"
17 #define cs_ratelimit "oscam.ratelimit"
18 #define cs_trid "oscam.tiers"
19 #define cs_sidt "oscam.services"
20 #define cs_whitelist "oscam.whitelist"
21 #define cs_provid "oscam.provid"
22 #define cs_fakecws "oscam.fakecws"
23 #define cs_twin "oscam.twin"
25 uint32_t cfg_sidtab_generation
= 1;
28 extern char cs_confdir
[];
30 char *get_config_filename(char *dest
, size_t destlen
, const char *filename
)
32 // cs_confdir is always terminated with /
33 snprintf(dest
, destlen
, "%s%s", cs_confdir
, filename
);
37 int32_t write_services(void)
40 struct s_sidtab
*sidtab
= cfg
.sidtab
;
42 FILE *f
= create_config_file(cs_sidt
);
51 if(*ptr
== ' ') { *ptr
= '_'; }
54 fprintf(f
, "[%s]\n", sidtab
->label
);
56 fprintf_conf(f
, "disablecrccws_only_for_exception", "%u", sidtab
->disablecrccws_only_for_exception
); // it should not have \n at the end
58 fprintf_conf(f
, "no_wait_time", "%u", sidtab
->no_wait_time
); // it should not have \n at the end
60 fprintf_conf(f
, "lg_only_exception", "%u", sidtab
->lg_only_exception
); // it should not have \n at the end
63 fprintf_conf(f
, "caid", "%s", ""); // it should not have \n at the end
64 for(i
= 0; i
< sidtab
->num_caid
; i
++)
66 if(i
== 0) { fprintf(f
, "%04X", sidtab
->caid
[i
]); }
67 else { fprintf(f
, ",%04X", sidtab
->caid
[i
]); }
70 fprintf_conf(f
, "provid", "%s", ""); // it should not have \n at the end
71 for(i
= 0; i
< sidtab
->num_provid
; i
++)
73 if(i
== 0) { fprintf(f
, "%06X", sidtab
->provid
[i
]); }
74 else { fprintf(f
, ",%06X", sidtab
->provid
[i
]); }
77 fprintf_conf(f
, "srvid", "%s", ""); // it should not have \n at the end
78 for(i
= 0; i
< sidtab
->num_srvid
; i
++)
80 if(i
== 0) { fprintf(f
, "%04X", sidtab
->srvid
[i
]); }
81 else { fprintf(f
, ",%04X", sidtab
->srvid
[i
]); }
84 sidtab
= sidtab
->next
;
87 return flush_config_file(f
, cs_sidt
);
90 void free_sidtab(struct s_sidtab
*ptr
)
93 add_garbage(ptr
->caid
); //no need to check on NULL first, freeing NULL doesnt do anything
94 add_garbage(ptr
->provid
);
95 add_garbage(ptr
->srvid
);
99 static void chk_entry4sidtab(char *value
, struct s_sidtab
*sidtab
, int32_t what
)
102 char *ptr
, *saveptr1
= NULL
;
103 uint16_t *slist
= (uint16_t *) 0;
104 uint32_t *llist
= (uint32_t *) 0;
105 #ifdef CS_CACHEEX_AIO
106 uint8_t disablecrccws_only_for_exception
= 0;
107 uint8_t no_wait_time
= 0;
108 uint8_t lg_only_exception
= 0;
110 char buf
[cs_strlen(value
) + 1];
111 cs_strncpy(buf
, value
, sizeof(buf
));
113 #ifdef CS_CACHEEX_AIO
114 if(what
== 5) // lg_only_exception
116 sidtab
->lg_only_exception
= a2i(buf
, sizeof(lg_only_exception
));
120 if(what
== 4) // no_wait_time
122 sidtab
->no_wait_time
= a2i(buf
, sizeof(no_wait_time
));
126 if(what
== 3) // disablecrccws_only_for_exception
128 sidtab
->disablecrccws_only_for_exception
= a2i(buf
, sizeof(disablecrccws_only_for_exception
));
133 b
= (what
== 1) ? sizeof(uint32_t) : sizeof(uint16_t);
135 for(i
= 0, ptr
= strtok_r(value
, ",", &saveptr1
); ptr
; ptr
= strtok_r(NULL
, ",", &saveptr1
))
141 if(b
== sizeof(uint16_t))
143 if(!cs_malloc(&slist
, i
* sizeof(uint16_t))) { return; }
147 if(!cs_malloc(&llist
, i
* sizeof(uint32_t))) { return; }
149 cs_strncpy(value
, buf
, sizeof(buf
));
150 for(i
= 0, ptr
= strtok_r(value
, ",", &saveptr1
); ptr
; ptr
= strtok_r(NULL
, ",", &saveptr1
))
153 if(errno
) { continue; }
154 if(b
== sizeof(uint16_t))
155 { slist
[i
++] = (uint16_t) caid
; }
157 { llist
[i
++] = caid
; }
162 add_garbage(sidtab
->caid
);
163 sidtab
->caid
= slist
;
164 sidtab
->num_caid
= i
;
167 add_garbage(sidtab
->provid
);
168 sidtab
->provid
= llist
;
169 sidtab
->num_provid
= i
;
172 add_garbage(sidtab
->srvid
);
173 sidtab
->srvid
= slist
;
174 sidtab
->num_srvid
= i
;
179 void chk_sidtab(char *token
, char *value
, struct s_sidtab
*sidtab
)
181 if(!strcmp(token
, "caid"))
183 chk_entry4sidtab(value
, sidtab
, 0);
186 if(!strcmp(token
, "provid"))
188 chk_entry4sidtab(value
, sidtab
, 1);
191 if(!strcmp(token
, "ident"))
193 chk_entry4sidtab(value
, sidtab
, 1);
196 if(!strcmp(token
, "srvid"))
198 chk_entry4sidtab(value
, sidtab
, 2);
201 #ifdef CS_CACHEEX_AIO
202 if(!strcmp(token
, "disablecrccws_only_for_exception"))
204 chk_entry4sidtab(value
, sidtab
, 3);
207 if(!strcmp(token
, "no_wait_time"))
209 chk_entry4sidtab(value
, sidtab
, 4);
212 if(!strcmp(token
, "lg_only_exception"))
214 chk_entry4sidtab(value
, sidtab
, 5);
219 { fprintf(stderr
, "Warning: keyword '%s' in sidtab section not recognized\n", token
); }
222 void init_free_sidtab(void)
224 struct s_sidtab
*nxt
, *ptr
= cfg
.sidtab
;
232 ++cfg_sidtab_generation
;
235 //#define DEBUG_SIDTAB 1
237 static void show_sidtab(struct s_sidtab
*sidtab
)
239 for(; sidtab
; sidtab
= sidtab
->next
)
244 cs_log("label=%s", sidtab
->label
);
245 #ifdef CS_CACHEEX_AIO
246 cs_log("disablecrccws_only_for_exception=%u", sidtab
->disablecrccws_only_for_exception
);
247 cs_log("no_wait_time=%u", sidtab
->no_wait_time
);
248 cs_log("lg_only_exception=%u", sidtab
->lg_only_exception
);
250 snprintf(buf
, sizeof(buf
), "caid(%d)=", sidtab
->num_caid
);
251 for(i
= 0; i
< sidtab
->num_caid
; i
++)
252 { snprintf(buf
+ cs_strlen(buf
), 1024 - (buf
- saveptr
), "%04X ", sidtab
->caid
[i
]); }
254 snprintf(buf
, sizeof(buf
), "provider(%d)=", sidtab
->num_provid
);
255 for(i
= 0; i
< sidtab
->num_provid
; i
++)
256 { snprintf(buf
+ cs_strlen(buf
), 1024 - (buf
- saveptr
), "%08X ", sidtab
->provid
[i
]); }
258 snprintf(buf
, sizeof(buf
), "services(%d)=", sidtab
->num_srvid
);
259 for(i
= 0; i
< sidtab
->num_srvid
; i
++)
260 { snprintf(buf
+ cs_strlen(buf
), 1024 - (buf
- saveptr
), "%04X ", sidtab
->srvid
[i
]); }
265 static void show_sidtab(struct s_sidtab
*UNUSED(sidtab
)) { }
268 int32_t init_sidtab(void)
270 FILE *fp
= open_config_file(cs_sidt
);
274 int32_t nr
, nro
, nrr
;
276 if(!cs_malloc(&token
, MAXLINESIZE
))
278 struct s_sidtab
*ptr
;
279 struct s_sidtab
*sidtab
= (struct s_sidtab
*)0;
281 for(nro
= 0, ptr
= cfg
.sidtab
; ptr
; nro
++)
283 struct s_sidtab
*ptr_next
;
284 ptr_next
= ptr
->next
;
290 while(fgets(token
, MAXLINESIZE
, fp
))
293 if((l
= cs_strlen(trim(token
))) < 3) { continue; }
294 if((token
[0] == '[') && (token
[l
- 1] == ']'))
299 fprintf(stderr
, "Warning: Service No.%d - '%s' ignored. Max allowed Services %d\n", nr
, strtolower(token
+ 1), MAX_SIDBITS
);
305 if(!cs_malloc(&ptr
, sizeof(struct s_sidtab
)))
311 { sidtab
->next
= ptr
; }
313 { cfg
.sidtab
= ptr
; }
316 cs_strncpy(sidtab
->label
, strtolower(token
+ 1), sizeof(sidtab
->label
));
320 if(!sidtab
) { continue; }
321 if(!(value
= strchr(token
, '='))) { continue; }
323 chk_sidtab(trim(strtolower(token
)), trim(strtolower(value
)), sidtab
);
328 show_sidtab(cfg
.sidtab
);
329 ++cfg_sidtab_generation
;
330 cs_log("services reloaded: %d services freed, %d services loaded, rejected %d", nro
, nr
, nrr
);
334 int32_t init_provid(void)
336 FILE *fp
= open_config_file(cs_provid
);
341 char *payload
, *saveptr1
= NULL
, *token
;
342 if(!cs_malloc(&token
, MAXLINESIZE
))
344 struct s_provid
*provid_ptr
= NULL
;
345 struct s_provid
*new_cfg_provid
= NULL
, *last_provid
;
348 while(fgets(token
, MAXLINESIZE
, fp
))
351 struct s_provid
*new_provid
= NULL
;
356 if(tmp
[0] == '#') { continue; }
357 if(cs_strlen(tmp
) < 11) { continue; }
358 if(!(payload
= strchr(token
, '|'))) { continue; }
362 if(!cs_malloc(&new_provid
, sizeof(struct s_provid
)))
369 new_provid
->nprovid
= 0;
370 for(i
= 0, ptr1
= strtok_r(token
, ":@", &saveptr1
); ptr1
; ptr1
= strtok_r(NULL
, ":@", &saveptr1
), i
++)
374 new_provid
->caid
= a2i(ptr1
, 3);
378 new_provid
->nprovid
++;
381 if(!cs_malloc(&new_provid
->provid
, sizeof(uint32_t) * new_provid
->nprovid
))
383 NULLFREE(new_provid
);
389 ptr1
= token
+ cs_strlen(token
) + 1;
390 for(i
= 0; i
< new_provid
->nprovid
; i
++)
392 new_provid
->provid
[i
] = a2i(ptr1
, 3);
394 ptr1
= ptr1
+ cs_strlen(ptr1
) + 1;
397 for(i
= 0, ptr1
= strtok_r(payload
, "|", &saveptr1
); ptr1
; ptr1
= strtok_r(NULL
, "|", &saveptr1
), i
++)
402 cs_strncpy(new_provid
->prov
, trim(ptr1
), sizeof(new_provid
->prov
));
405 cs_strncpy(new_provid
->sat
, trim(ptr1
), sizeof(new_provid
->sat
));
408 cs_strncpy(new_provid
->lang
, trim(ptr1
), sizeof(new_provid
->lang
));
413 if(cs_strlen(new_provid
->prov
) == 0)
415 NULLFREE(new_provid
->provid
);
416 NULLFREE(new_provid
);
424 provid_ptr
->next
= new_provid
;
428 new_cfg_provid
= new_provid
;
430 provid_ptr
= new_provid
;
437 { cs_log("%d provid's loaded", nr
); }
439 if(new_cfg_provid
== NULL
)
441 if(!cs_malloc(&new_cfg_provid
, sizeof(struct s_provid
)))
447 cs_writelock(__func__
, &config_lock
);
449 // this allows reloading of provids, so cleanup of old data is needed:
450 last_provid
= cfg
.provid
; // old data
451 cfg
.provid
= new_cfg_provid
; // assign after loading, so everything is in memory
453 cs_writeunlock(__func__
, &config_lock
);
456 for(cl
= first_client
->next
; cl
; cl
= cl
->next
)
457 { cl
->last_providptr
= NULL
; }
459 struct s_provid
*ptr
, *nptr
;
464 while(ptr
) // cleanup old data:
466 add_garbage(ptr
->provid
);
476 int32_t init_srvid(void)
478 int8_t new_syntax
= 1;
479 FILE *fp
= open_config_file("oscam.srvid2");
482 fp
= open_config_file(cs_srid
);
491 fp
= create_config_file("oscam.srvid2");
494 flush_config_file(fp
, "oscam.srvid2");
500 int32_t nr
= 0, i
, j
;
501 char *payload
, *saveptr1
= NULL
, *saveptr2
= NULL
, *token
;
503 if(!cs_malloc(&token
, MAXLINESIZE
))
505 struct s_srvid
*srvid
= NULL
, *new_cfg_srvid
[16], *last_srvid
[16];
506 // A cache for strings within srvids. A checksum is calculated which is the start point in the array (some kind of primitive hash algo).
507 // From this point, a sequential search is done. This greatly reduces the amount of string comparisons.
508 const char **stringcache
[1024];
509 int32_t allocated
[1024] = { 0 };
510 int32_t used
[1024] = { 0 };
514 memset(last_srvid
, 0, sizeof(last_srvid
));
515 memset(new_cfg_srvid
, 0, sizeof(new_cfg_srvid
));
517 while(fgets(token
, MAXLINESIZE
, fp
))
519 int32_t len
= 0, len2
, srvidtmp
;
522 char *srvidasc
, *prov
;
525 if(tmp
[0] == '#') { continue; }
526 if(cs_strlen(tmp
) < 6) { continue; }
527 if(!(srvidasc
= strchr(token
, ':'))) { continue; }
528 if(!(payload
= strchr(token
, '|'))) { continue; }
531 if(!cs_malloc(&srvid
, sizeof(struct s_srvid
)))
540 int32_t offset
[4] = { -1, -1, -1, -1 };
541 char *ptr1
= NULL
, *ptr2
= NULL
;
542 const char *searchptr
[4] = { NULL
, NULL
, NULL
, NULL
};
543 const char **ptrs
[4] = { &srvid
->prov
, &srvid
->name
, &srvid
->type
, &srvid
->desc
};
544 uint32_t max_payload_length
= MAXLINESIZE
- (payload
- token
);
548 ptrs
[0] = &srvid
->name
;
549 ptrs
[1] = &srvid
->type
;
550 ptrs
[2] = &srvid
->desc
;
551 ptrs
[3] = &srvid
->prov
;
554 // allow empty strings as "||"
555 if(payload
[0] == '|' && (cs_strlen(payload
) + 2 < max_payload_length
))
557 memmove(payload
+1, payload
, cs_strlen(payload
)+1);
561 for(k
= 1; ((k
< max_payload_length
) && (payload
[k
] != '\0')); k
++)
563 if(payload
[k
- 1] == '|' && payload
[k
] == '|')
565 if(cs_strlen(payload
+ k
) + 2 < max_payload_length
-k
)
567 memmove(payload
+ k
+ 1, payload
+ k
, cs_strlen(payload
+ k
) + 1);
577 for(i
= 0, ptr1
= strtok_r(payload
, "|", &saveptr1
); ptr1
&& (i
< 4) ; ptr1
= strtok_r(NULL
, "|", &saveptr1
), ++i
)
579 // check if string is in cache
580 len2
= cs_strlen(ptr1
);
582 for(j
= 0; j
< len2
; ++j
) { pos
+= (uint8_t)ptr1
[j
]; }
584 for(j
= 0; j
< used
[pos
]; ++j
)
586 if(!strcmp(stringcache
[pos
][j
], ptr1
))
588 searchptr
[i
] = stringcache
[pos
][j
];
592 if(searchptr
[i
]) { continue; }
595 cs_strncpy(tmptxt
+ len
, trim(ptr1
), sizeof(tmptxt
) - len
);
596 len
+= cs_strlen(ptr1
) + 1;
600 if(len
> 0 && !cs_malloc(&tmpptr
, len
))
603 srvid
->data
= tmpptr
;
604 if(len
> 0) { memcpy(tmpptr
, tmptxt
, len
); }
606 for(i
= 0; i
< 4; i
++)
610 *ptrs
[i
] = searchptr
[i
];
615 *ptrs
[i
] = tmpptr
+ offset
[i
];
616 // store string in stringcache
620 len2
= cs_strlen(tmp
);
624 cs_log("FIXME! len2!");
629 for(j
= 0; j
< len2
; ++j
) { pos
+= (uint8_t)tmp
[j
]; }
634 if(used
[pos
] >= allocated
[pos
])
636 if(allocated
[pos
] == 0)
638 if(!cs_malloc(&stringcache
[pos
], 16 * sizeof(char *)))
643 if(!cs_realloc(&stringcache
[pos
], (allocated
[pos
] + 16) * sizeof(char *)))
646 allocated
[pos
] += 16;
650 stringcache
[pos
][used
[pos
]] = tmp
;
658 { srvidtmp
= dyn_word_atob(token
) & 0xFFFF; }
660 { srvidtmp
= dyn_word_atob(srvidasc
) & 0xFFFF; }
670 srvid
->srvid
= srvidtmp
;
674 for(i
= 0, ptr1
= strtok_r(new_syntax
? srvidasc
: token
, ",", &saveptr1
); (ptr1
); ptr1
= strtok_r(NULL
, ",", &saveptr1
), i
++)
679 if(!cs_malloc(&srvid
->caid
, sizeof(struct s_srvid_caid
) * srvid
->ncaid
))
686 ptr1
= new_syntax
? srvidasc
: token
;
687 for(i
= 0; i
< srvid
->ncaid
; i
++)
689 prov
= strchr(ptr1
,'@');
691 srvid
->caid
[i
].nprovid
= 0;
697 for(j
= 0, ptr2
= strtok_r(prov
+1, "@", &saveptr2
); (ptr2
); ptr2
= strtok_r(NULL
, "@", &saveptr2
), j
++)
699 srvid
->caid
[i
].nprovid
++;
702 if(!cs_malloc(&srvid
->caid
[i
].provid
, sizeof(uint32_t) * srvid
->caid
[i
].nprovid
))
704 for(j
= 0; j
< i
; j
++)
705 { NULLFREE(srvid
->caid
[j
].provid
); }
706 NULLFREE(srvid
->caid
);
713 for(j
= 0; j
< srvid
->caid
[i
].nprovid
; j
++)
715 srvid
->caid
[i
].provid
[j
] = dyn_word_atob(ptr2
) & 0xFFFFFF;
716 ptr2
= ptr2
+ cs_strlen(ptr2
) + 1;
727 srvid
->caid
[i
].caid
= dyn_word_atob(ptr1
) & 0xFFFF;
731 { ptr1
= ptr1
+ cs_strlen(ptr1
) + 1; }
736 if(new_cfg_srvid
[srvid
->srvid
>> 12])
737 { last_srvid
[srvid
->srvid
>> 12]->next
= srvid
; }
739 { new_cfg_srvid
[srvid
->srvid
>> 12] = srvid
; }
741 last_srvid
[srvid
->srvid
>> 12] = srvid
;
743 for(i
= 0; i
< 1024; ++i
)
745 if(allocated
[i
] > 0) { NULLFREE(stringcache
[i
]); }
750 int64_t load_time
= comp_timeb(&te
, &ts
);
755 cs_log("%d service-id's loaded in %"PRId64
" ms", nr
, load_time
);
758 cs_log("WARNING: You risk high CPU load and high ECM times with more than 2000 service-id's!");
759 cs_log("HINT: --> use optimized lists from https://wiki.streamboard.tv/wiki/Srvid");
763 cs_writelock(__func__
, &config_lock
);
764 // this allows reloading of srvids, so cleanup of old data is needed:
765 memcpy(last_srvid
, cfg
.srvid
, sizeof(last_srvid
)); //old data
766 memcpy(cfg
.srvid
, new_cfg_srvid
, sizeof(last_srvid
)); //assign after loading, so everything is in memory
768 cs_writeunlock(__func__
, &config_lock
);
771 for(cl
= first_client
->next
; cl
; cl
= cl
->next
)
772 { cl
->last_srvidptr
= NULL
; }
774 struct s_srvid
*ptr
, *nptr
;
776 for(i
= 0; i
< 16; i
++)
779 while(ptr
) // cleanup old data:
781 for(j
= 0; j
< ptr
->ncaid
; j
++)
782 { add_garbage(ptr
->caid
[j
].provid
); }
783 add_garbage(ptr
->caid
);
784 add_garbage(ptr
->data
);
794 int32_t init_fakecws(void)
796 int32_t nr
= 0, i
, j
, idx
;
797 uint32_t alloccount
[0x100], count
[0x100], tmp
, max_compares
= 0, average_compares
= 0;
798 char *token
, cw_string
[64];
799 uint8_t cw
[16], wrong_checksum
, c
, have_fakecw
= 0;
802 memset(alloccount
, 0, sizeof(count
));
803 memset(count
, 0, sizeof(alloccount
));
805 cs_writelock(__func__
, &config_lock
);
806 for(i
= 0; i
< 0x100; i
++)
808 cfg
.fakecws
[i
].count
= 0;
809 NULLFREE(cfg
.fakecws
[i
].data
);
811 cs_writeunlock(__func__
, &config_lock
);
813 fp
= open_config_file(cs_fakecws
);
817 if(!cs_malloc(&token
, MAXLINESIZE
))
820 while(fgets(token
, MAXLINESIZE
, fp
))
822 if(sscanf(token
, " %62s ", cw_string
) == 1)
824 if(cs_strlen(cw_string
) == 32)
826 if(cs_atob(cw
, cw_string
, 16) == 16)
830 for(i
= 0; i
< 16; i
+= 4)
832 c
= ((cw
[i
] + cw
[i
+ 1] + cw
[i
+ 2]) & 0xff);
841 cs_log("skipping fake cw %s because of wrong checksum!", cw_string
);
845 idx
= ((cw
[0] & 0xF) << 4) | (cw
[8] & 0xF);
852 cs_log("skipping fake cw %s because it contains invalid characters!", cw_string
);
857 cs_log("skipping fake cw %s because of wrong length (%u != 32)!", cw_string
, (uint32_t)cs_strlen(cw_string
));
869 for(i
= 0; i
< 0x100; i
++)
871 if(alloccount
[i
] && !cs_malloc(&cfg
.fakecws
[i
].data
, sizeof(struct s_cw
)*alloccount
[i
]))
877 fseek(fp
, 0, SEEK_SET
);
879 while(fgets(token
, MAXLINESIZE
, fp
))
881 if(sscanf(token
, " %62s ", cw_string
) == 1)
883 if(cs_strlen(cw_string
) == 32)
885 if(cs_atob(cw
, cw_string
, 16) == 16)
889 for(i
= 0; i
< 16; i
+= 4)
891 c
= ((cw
[i
] + cw
[i
+ 1] + cw
[i
+ 2]) & 0xff);
900 idx
= ((cw
[0] & 0xF) << 4) | (cw
[8] & 0xF);
902 if(count
[idx
] < alloccount
[idx
])
904 memcpy(cfg
.fakecws
[idx
].data
[count
[idx
]].cw
, cw
, 16);
918 { cs_log("%d fakecws's loaded", nr
); }
921 cs_writelock(__func__
, &config_lock
);
922 for(i
= 0; i
< 0x100; i
++)
924 cfg
.fakecws
[i
].count
= count
[i
];
926 cs_writeunlock(__func__
, &config_lock
);
929 for(i
= 0; i
< 0x100; i
++)
931 if(count
[i
] > max_compares
)
932 { max_compares
= count
[i
]; }
935 for(i
= 0; i
< (0x100 - 1); i
++)
937 for(j
= i
+ 1; j
< 0x100; j
++)
939 if(count
[j
] < count
[i
])
947 average_compares
= ((count
[0x100 / 2] + count
[0x100 / 2 - 1]) / 2);
950 cs_log("max %d fakecw compares required, on average: %d compares", max_compares
, average_compares
);
955 static struct s_rlimit
*ratelimit_read_int(void)
957 FILE *fp
= open_config_file(cs_ratelimit
);
960 char token
[1024], str1
[1024];
961 int32_t i
, ret
, count
= 0;
962 struct s_rlimit
*new_rlimit
= NULL
, *entry
, *last
= NULL
;
965 while(fgets(token
, sizeof(token
), fp
))
968 if(cs_strlen(token
) <= 1) { continue; }
969 if(token
[0] == '#' || token
[0] == '/') { continue; }
970 if(cs_strlen(token
) > 1024) { continue; }
972 for(i
= 0; i
< (int)cs_strlen(token
); i
++)
974 if((token
[i
] == ':' || token
[i
] == ' ') && token
[i
+ 1] == ':')
976 memmove(token
+ i
+ 2, token
+ i
+ 1, cs_strlen(token
) - i
+ 1);
979 if(token
[i
] == '#' || token
[i
] == '/')
987 uint32_t provid
= 0, srvid
= 0, chid
= 0, ratelimitecm
= 0, ratelimittime
= 0, srvidholdtime
= 0;
988 memset(str1
, 0, sizeof(str1
));
990 ret
= sscanf(token
, "%4x:%6x:%4x:%4x:%d:%d:%d:%1023s", &caid
, &provid
, &srvid
, &chid
, &ratelimitecm
, &ratelimittime
, &srvidholdtime
, str1
);
995 if (!cs_strncat(str1
, ",", sizeof(str1
))) {
999 if(!cs_malloc(&entry
, sizeof(struct s_rlimit
)))
1006 if (ratelimittime
< 60) ratelimittime
*= 1000;
1007 if (srvidholdtime
< 60) srvidholdtime
*= 1000;
1008 entry
->rl
.caid
= caid
;
1009 entry
->rl
.provid
= provid
;
1010 entry
->rl
.srvid
= srvid
;
1011 entry
->rl
.chid
= chid
;
1012 entry
->rl
.ratelimitecm
= ratelimitecm
;
1013 entry
->rl
.ratelimittime
= ratelimittime
;
1014 entry
->rl
.srvidholdtime
= srvidholdtime
;
1016 cs_log_dbg(D_TRACE
, "ratelimit: %04X@%06X:%04X:%04X:%d:%d:%d", entry
->rl
.caid
, entry
->rl
.provid
, entry
->rl
.srvid
, entry
->rl
.chid
,
1017 entry
->rl
.ratelimitecm
, entry
->rl
.ratelimittime
, entry
->rl
.srvidholdtime
);
1032 { cs_log("%d entries read from %s", count
, cs_ratelimit
); }
1039 void ratelimit_read(void)
1042 struct s_rlimit
*entry
, *old_list
;
1044 old_list
= cfg
.ratelimit_list
;
1045 cfg
.ratelimit_list
= ratelimit_read_int();
1049 entry
= old_list
->next
;
1055 struct ecmrl
get_ratelimit(ECM_REQUEST
*er
)
1059 memset(&tmp
, 0, sizeof(tmp
));
1060 if(!cfg
.ratelimit_list
) { return tmp
; }
1061 struct s_rlimit
*entry
= cfg
.ratelimit_list
;
1064 if(entry
->rl
.caid
== er
->caid
&& entry
->rl
.provid
== er
->prid
&& entry
->rl
.srvid
== er
->srvid
&& (!entry
->rl
.chid
|| entry
->rl
.chid
== er
->chid
))
1068 entry
= entry
->next
;
1071 if(entry
) { tmp
= entry
->rl
; }
1076 int32_t init_tierid(void)
1078 FILE *fp
= open_config_file(cs_trid
);
1083 char *payload
, *saveptr1
= NULL
, *token
;
1084 if(!cs_malloc(&token
, MAXLINESIZE
))
1086 static struct s_tierid
*tierid
= NULL
, *new_cfg_tierid
= NULL
;
1089 while(fgets(token
, MAXLINESIZE
, fp
))
1092 char *tmp
, *tieridasc
;
1095 if(tmp
[0] == '#') { continue; }
1096 if(cs_strlen(tmp
) < 6) { continue; }
1097 if(!(payload
= strchr(token
, '|'))) { continue; }
1098 if(!(tieridasc
= strchr(token
, ':'))) { continue; }
1101 if(!cs_malloc(&ptr
, sizeof(struct s_tierid
)))
1108 { tierid
->next
= ptr
; }
1110 { new_cfg_tierid
= ptr
; }
1115 char *ptr1
= strtok_r(payload
, "|", &saveptr1
);
1117 { cs_strncpy(tierid
->name
, trim(ptr1
), sizeof(tierid
->name
)); }
1119 *tieridasc
++ = '\0';
1120 tierid
->tierid
= dyn_word_atob(tieridasc
);
1121 //printf("tierid %s - %d\n",tieridasc,tierid->tierid );
1124 for(i
= 0, ptr1
= strtok_r(token
, ",", &saveptr1
); (ptr1
) && (i
< 10) ; ptr1
= strtok_r(NULL
, ",", &saveptr1
), i
++)
1126 tierid
->caid
[i
] = dyn_word_atob(ptr1
);
1127 tierid
->ncaid
= i
+ 1;
1128 //cs_log("ld caid: %04X tierid: %04X name: %s",tierid->caid[i],tierid->tierid,tierid->name);
1135 { cs_log("%d tier-id's loaded", nr
); }
1136 cs_writelock(__func__
, &config_lock
);
1138 tierid
= cfg
.tierid
;
1139 cfg
.tierid
= new_cfg_tierid
;
1140 struct s_tierid
*ptr
;
1147 cs_writeunlock(__func__
, &config_lock
);
1152 int32_t match_whitelist(ECM_REQUEST
*er
, struct s_global_whitelist
*entry
)
1154 return ((!entry
->caid
|| entry
->caid
== er
->caid
)
1155 && (!entry
->provid
|| entry
->provid
== er
->prid
)
1156 && (!entry
->srvid
|| entry
->srvid
== er
->srvid
)
1157 && (!entry
->chid
|| entry
->chid
== er
->chid
)
1158 && (!entry
->pid
|| entry
->pid
== er
->pid
)
1159 && (!entry
->ecmlen
|| entry
->ecmlen
== er
->ecmlen
));
1162 int32_t chk_global_whitelist(ECM_REQUEST
*er
, uint32_t *line
)
1165 if(!cfg
.global_whitelist
)
1168 struct s_global_whitelist
*entry
;
1171 if(cfg
.global_whitelist_use_m
)
1173 entry
= cfg
.global_whitelist
;
1176 if(entry
->type
== 'm')
1178 if(match_whitelist(er
, entry
))
1180 cs_log_dbg(D_TRACE
, "whitelist: mapped %04X@%06X to %04X@%06X", er
->caid
, er
->prid
, entry
->mapcaid
, entry
->mapprovid
);
1181 er
->caid
= entry
->mapcaid
;
1182 er
->prid
= entry
->mapprovid
;
1186 entry
= entry
->next
;
1190 if(cfg
.global_whitelist_use_l
) // Check caid/prov/srvid etc matching, except ecm-len:
1192 entry
= cfg
.global_whitelist
;
1193 int8_t caidprov_matches
= 0;
1196 if(entry
->type
== 'l')
1198 if(match_whitelist(er
, entry
))
1200 *line
= entry
->line
;
1203 if((!entry
->caid
|| entry
->caid
== er
->caid
)
1204 && (!entry
->provid
|| entry
->provid
== er
->prid
)
1205 && (!entry
->srvid
|| entry
->srvid
== er
->srvid
)
1206 && (!entry
->chid
|| entry
->chid
== er
->chid
)
1207 && (!entry
->pid
|| entry
->pid
== er
->pid
))
1209 caidprov_matches
= 1;
1210 *line
= entry
->line
;
1213 entry
= entry
->next
;
1215 if(caidprov_matches
) // ...but not ecm-len!
1219 entry
= cfg
.global_whitelist
;
1222 if(match_whitelist(er
, entry
))
1224 *line
= entry
->line
;
1225 if(entry
->type
== 'w')
1227 else if(entry
->type
== 'i')
1230 entry
= entry
->next
;
1237 //w:caid:prov:srvid:pid:chid:ecmlen
1239 //i:caid:prov:srvid:pid:chid:ecmlen
1240 //ECM len check - Entry:
1241 //l:caid:prov:srvid:pid:chid:ecmlen
1244 //m:caid:prov:srvid:pid:chid:ecmlen caidto:provto
1246 static struct s_global_whitelist
*global_whitelist_read_int(void)
1248 FILE *fp
= open_config_file(cs_whitelist
);
1252 char token
[1024], str1
[1024];
1254 int32_t i
, ret
, count
= 0;
1255 struct s_global_whitelist
*new_whitelist
= NULL
, *entry
, *last
= NULL
;
1258 cfg
.global_whitelist_use_l
= 0;
1259 cfg
.global_whitelist_use_m
= 0;
1261 while(fgets(token
, sizeof(token
), fp
))
1264 if(cs_strlen(token
) <= 1) { continue; }
1265 if(token
[0] == '#' || token
[0] == '/') { continue; }
1266 if(cs_strlen(token
) > 1024) { continue; }
1268 for(i
= 0; i
< (int)cs_strlen(token
); i
++)
1270 if((token
[i
] == ':' || token
[i
] == ' ') && token
[i
+ 1] == ':')
1272 memmove(token
+ i
+ 2, token
+ i
+ 1, cs_strlen(token
) - i
+ 1);
1275 if(token
[i
] == '#' || token
[i
] == '/')
1284 uint32_t provid
= 0, srvid
= 0, pid
= 0, chid
= 0, ecmlen
= 0, mapcaid
= 0, mapprovid
= 0;
1285 memset(str1
, 0, sizeof(str1
));
1287 ret
= sscanf(token
, "%c:%4x:%6x:%4x:%4x:%4x:%1023s", &type
, &caid
, &provid
, &srvid
, &pid
, &chid
, str1
);
1289 type
= tolower(type
);
1295 if(ret
< 1 || (type
!= 'w' && type
!= 'i' && type
!= 'l' && type
!= 'm'))
1300 char *p
= strstr(token
+ 4, " ");
1301 if(!p
|| sscanf(p
+ 1, "%4x:%6x", &mapcaid
, &mapprovid
) < 2)
1303 cs_log_dbg(D_TRACE
, "whitelist: wrong mapping: %s", token
);
1307 cfg
.global_whitelist_use_m
= 1;
1310 if (!cs_strncat(str1
, ",", sizeof(str1
))) {
1311 return new_whitelist
;
1314 char *p
= str1
, *p2
= str1
;
1322 sscanf(p2
, "%4x", &ecmlen
);
1324 if(!cs_malloc(&entry
, sizeof(struct s_global_whitelist
)))
1327 return new_whitelist
;
1334 entry
->provid
= provid
;
1335 entry
->srvid
= srvid
;
1338 entry
->ecmlen
= ecmlen
;
1339 entry
->mapcaid
= mapcaid
;
1340 entry
->mapprovid
= mapprovid
;
1341 if(entry
->type
== 'l')
1342 { cfg
.global_whitelist_use_l
= 1; }
1345 cs_log_dbg(D_TRACE
, "whitelist: %c: %04X@%06X:%04X:%04X:%04X:%02X map to %04X@%06X",
1346 entry
->type
, entry
->caid
, entry
->provid
, entry
->srvid
, entry
->pid
, entry
->chid
, entry
->ecmlen
, entry
->mapcaid
, entry
->mapprovid
);
1348 cs_log_dbg(D_TRACE
, "whitelist: %c: %04X@%06X:%04X:%04X:%04X:%02X",
1349 entry
->type
, entry
->caid
, entry
->provid
, entry
->srvid
, entry
->pid
, entry
->chid
, entry
->ecmlen
);
1353 new_whitelist
= entry
;
1354 last
= new_whitelist
;
1369 { cs_log("%d entries read from %s", count
, cs_whitelist
); }
1373 return new_whitelist
;
1376 void global_whitelist_read(void)
1378 struct s_global_whitelist
*entry
, *old_list
;
1380 old_list
= cfg
.global_whitelist
;
1381 cfg
.global_whitelist
= global_whitelist_read_int();
1385 entry
= old_list
->next
;
1391 #ifdef MODULE_SERIAL
1392 static struct s_twin
*twin_read_int(void)
1394 FILE *fp
= open_config_file(cs_twin
);
1397 char token
[1024], str1
[1024];
1398 int32_t i
, ret
, count
= 0;
1399 struct s_twin
*new_twin
= NULL
, *entry
, *last
= NULL
;
1402 while(fgets(token
, sizeof(token
), fp
))
1405 if(cs_strlen(token
) <= 1) { continue; }
1406 if(token
[0] == '#' || token
[0] == '/') { continue; }
1407 if(cs_strlen(token
) > 1024) { continue; }
1409 for(i
= 0; i
< (int)cs_strlen(token
); i
++)
1411 if((token
[i
] == ':' || token
[i
] == ' ') && token
[i
+ 1] == ':')
1413 memmove(token
+ i
+ 2, token
+ i
+ 1, cs_strlen(token
) - i
+ 1);
1416 if(token
[i
] == '#' || token
[i
] == '/' || token
[i
] == '"')
1424 uint32_t provid
= 0, srvid
= 0, deg
= 0, freq
= 0;
1425 //char hdeg[4], hfreq[4], hsrvid[4];
1426 memset(str1
, 0, sizeof(str1
));
1428 ret
= sscanf(token
, "%4x:%6x:%d:%d:%d", &caid
, &provid
, °
, &freq
, &srvid
);
1429 if(ret
< 1) { continue; }
1431 //snprintf(hdeg, 4, "%x", deg);
1432 //sscanf(hdeg, "%4x", °);
1433 //snprintf(hfreq, 4, "%x", freq);
1434 //sscanf(hfreq, "%4x", &freq);
1435 //snprintf(hsrvid, 4, "%x", srvid);
1436 //sscanf(hsrvid, "%4x", &srvid);
1437 if (!cs_strncat(str1
, ",", sizeof(str1
))) {
1441 if(!cs_malloc(&entry
, sizeof(struct s_twin
)))
1448 entry
->tw
.caid
= caid
;
1449 entry
->tw
.provid
= provid
;
1450 entry
->tw
.srvid
= srvid
;
1451 entry
->tw
.deg
= deg
;
1452 entry
->tw
.freq
= freq
;
1454 cs_debug_mask(D_TRACE
, "channel: %04X:%06X:%d:%d:%d", entry
->tw
.caid
,
1455 entry
->tw
.provid
, entry
->tw
.deg
, entry
->tw
.freq
, entry
->tw
.srvid
);
1470 { cs_log("%d entries read from %s", count
, cs_twin
); }
1477 void twin_read(void)
1480 struct s_twin
*entry
, *old_list
;
1482 old_list
= cfg
.twin_list
;
1483 cfg
.twin_list
= twin_read_int();
1487 entry
= old_list
->next
;
1493 struct ecmtw
get_twin(ECM_REQUEST
*er
)
1496 memset(&tmp
, 0, sizeof(tmp
));
1499 cs_log("twin_list not found!");
1502 struct s_twin
*entry
= cfg
.twin_list
;
1505 if(entry
->tw
.caid
== er
->caid
&& entry
->tw
.provid
== er
->prid
&& entry
->tw
.srvid
== er
->srvid
)
1509 entry
= entry
->next
;
1512 if(entry
) { tmp
= entry
->tw
; }