- fix Building without Nagra not possible at Nagra_Merlin https://trac.streamboard...
[oscam.git] / oscam-config.c
blobf4bdfeb89afc0cf35cf2d535922800093265aa7a
1 #define MODULE_LOG_PREFIX "config"
3 //FIXME Not checked on threadsafety yet; after checking please remove this line
5 #include "globals.h"
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;
26 uint32_t caid;
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);
34 return dest;
37 int32_t write_services(void)
39 int32_t i;
40 struct s_sidtab *sidtab = cfg.sidtab;
41 char *ptr;
42 FILE *f = create_config_file(cs_sidt);
43 if(!f)
44 { return 1; }
46 while(sidtab != NULL)
48 ptr = sidtab->label;
49 while(*ptr)
51 if(*ptr == ' ') { *ptr = '_'; }
52 ptr++;
54 fprintf(f, "[%s]\n", sidtab->label);
55 #ifdef CS_CACHEEX_AIO
56 fprintf_conf(f, "disablecrccws_only_for_exception", "%u", sidtab->disablecrccws_only_for_exception); // it should not have \n at the end
57 fputc((int)'\n', f);
58 fprintf_conf(f, "no_wait_time", "%u", sidtab->no_wait_time); // it should not have \n at the end
59 fputc((int)'\n', f);
60 fprintf_conf(f, "lg_only_exception", "%u", sidtab->lg_only_exception); // it should not have \n at the end
61 fputc((int)'\n', f);
62 #endif
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]); }
69 fputc((int)'\n', f);
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]); }
76 fputc((int)'\n', f);
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]); }
83 fprintf(f, "\n\n");
84 sidtab = sidtab->next;
87 return flush_config_file(f, cs_sidt);
90 void free_sidtab(struct s_sidtab *ptr)
92 if(!ptr) { return; }
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);
96 add_garbage(ptr);
99 static void chk_entry4sidtab(char *value, struct s_sidtab *sidtab, int32_t what)
101 int32_t i, b;
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;
109 #endif
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));
117 return;
120 if(what == 4) // no_wait_time
122 sidtab->no_wait_time = a2i(buf, sizeof(no_wait_time));
123 return;
126 if(what == 3) // disablecrccws_only_for_exception
128 sidtab->disablecrccws_only_for_exception = a2i(buf, sizeof(disablecrccws_only_for_exception));
129 return;
131 #endif
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))
137 caid = a2i(ptr, b);
138 if(!errno) { i++; }
140 //if (!i) return(0);
141 if(b == sizeof(uint16_t))
143 if(!cs_malloc(&slist, i * sizeof(uint16_t))) { return; }
145 else
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))
152 caid = a2i(ptr, b);
153 if(errno) { continue; }
154 if(b == sizeof(uint16_t))
155 { slist[i++] = (uint16_t) caid; }
156 else
157 { llist[i++] = caid; }
159 switch(what)
161 case 0:
162 add_garbage(sidtab->caid);
163 sidtab->caid = slist;
164 sidtab->num_caid = i;
165 break;
166 case 1:
167 add_garbage(sidtab->provid);
168 sidtab->provid = llist;
169 sidtab->num_provid = i;
170 break;
171 case 2:
172 add_garbage(sidtab->srvid);
173 sidtab->srvid = slist;
174 sidtab->num_srvid = i;
175 break;
179 void chk_sidtab(char *token, char *value, struct s_sidtab *sidtab)
181 if(!strcmp(token, "caid"))
183 chk_entry4sidtab(value, sidtab, 0);
184 return;
186 if(!strcmp(token, "provid"))
188 chk_entry4sidtab(value, sidtab, 1);
189 return;
191 if(!strcmp(token, "ident"))
193 chk_entry4sidtab(value, sidtab, 1);
194 return;
196 if(!strcmp(token, "srvid"))
198 chk_entry4sidtab(value, sidtab, 2);
199 return;
201 #ifdef CS_CACHEEX_AIO
202 if(!strcmp(token, "disablecrccws_only_for_exception"))
204 chk_entry4sidtab(value, sidtab, 3);
205 return;
207 if(!strcmp(token, "no_wait_time"))
209 chk_entry4sidtab(value, sidtab, 4);
210 return;
212 if(!strcmp(token, "lg_only_exception"))
214 chk_entry4sidtab(value, sidtab, 5);
215 return;
217 #endif
218 if(token[0] != '#')
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;
225 while(ptr)
227 nxt = ptr->next;
228 free_sidtab(ptr);
229 ptr = nxt;
231 cfg.sidtab = NULL;
232 ++cfg_sidtab_generation;
235 //#define DEBUG_SIDTAB 1
236 #ifdef DEBUG_SIDTAB
237 static void show_sidtab(struct s_sidtab *sidtab)
239 for(; sidtab; sidtab = sidtab->next)
241 int32_t i;
242 char buf[1024];
243 char *saveptr = buf;
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);
249 #endif
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]); }
253 cs_log("%s", buf);
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]); }
257 cs_log("%s", buf);
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]); }
261 cs_log("%s", buf);
264 #else
265 static void show_sidtab(struct s_sidtab *UNUSED(sidtab)) { }
266 #endif
268 int32_t init_sidtab(void)
270 FILE *fp = open_config_file(cs_sidt);
271 if(!fp)
272 { return 1; }
274 int32_t nr, nro, nrr;
275 char *value, *token;
276 if(!cs_malloc(&token, MAXLINESIZE))
277 { return 1; }
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;
285 free_sidtab(ptr);
286 ptr = ptr_next;
288 nr = 0;
289 nrr = 0;
290 while(fgets(token, MAXLINESIZE, fp))
292 int32_t l;
293 if((l = cs_strlen(trim(token))) < 3) { continue; }
294 if((token[0] == '[') && (token[l - 1] == ']'))
296 token[l - 1] = 0;
297 if(nr > MAX_SIDBITS)
299 fprintf(stderr, "Warning: Service No.%d - '%s' ignored. Max allowed Services %d\n", nr, strtolower(token + 1), MAX_SIDBITS);
300 nr++;
301 nrr++;
303 else
305 if(!cs_malloc(&ptr, sizeof(struct s_sidtab)))
307 NULLFREE(token);
308 return (1);
310 if(sidtab)
311 { sidtab->next = ptr; }
312 else
313 { cfg.sidtab = ptr; }
314 sidtab = ptr;
315 nr++;
316 cs_strncpy(sidtab->label, strtolower(token + 1), sizeof(sidtab->label));
317 continue;
320 if(!sidtab) { continue; }
321 if(!(value = strchr(token, '='))) { continue; }
322 *value++ = '\0';
323 chk_sidtab(trim(strtolower(token)), trim(strtolower(value)), sidtab);
325 NULLFREE(token);
326 fclose(fp);
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);
331 return (0);
334 int32_t init_provid(void)
336 FILE *fp = open_config_file(cs_provid);
337 if(!fp)
338 { return 0; }
340 int32_t nr;
341 char *payload, *saveptr1 = NULL, *token;
342 if(!cs_malloc(&token, MAXLINESIZE))
343 { return 0; }
344 struct s_provid *provid_ptr = NULL;
345 struct s_provid *new_cfg_provid = NULL, *last_provid;
347 nr = 0;
348 while(fgets(token, MAXLINESIZE, fp))
350 int32_t i;
351 struct s_provid *new_provid = NULL;
352 char *tmp, *ptr1;
354 tmp = trim(token);
356 if(tmp[0] == '#') { continue; }
357 if(cs_strlen(tmp) < 11) { continue; }
358 if(!(payload = strchr(token, '|'))) { continue; }
360 *payload++ = '\0';
362 if(!cs_malloc(&new_provid, sizeof(struct s_provid)))
364 NULLFREE(token);
365 fclose(fp);
366 return (1);
369 new_provid->nprovid = 0;
370 for(i = 0, ptr1 = strtok_r(token, ":@", &saveptr1); ptr1; ptr1 = strtok_r(NULL, ":@", &saveptr1), i++)
372 if(i==0)
374 new_provid->caid = a2i(ptr1, 3);
375 continue;
378 new_provid->nprovid++;
381 if(!cs_malloc(&new_provid->provid, sizeof(uint32_t) * new_provid->nprovid))
383 NULLFREE(new_provid);
384 NULLFREE(token);
385 fclose(fp);
386 return (1);
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++)
399 switch(i)
401 case 0:
402 cs_strncpy(new_provid->prov, trim(ptr1), sizeof(new_provid->prov));
403 break;
404 case 1:
405 cs_strncpy(new_provid->sat, trim(ptr1), sizeof(new_provid->sat));
406 break;
407 case 2:
408 cs_strncpy(new_provid->lang, trim(ptr1), sizeof(new_provid->lang));
409 break;
413 if(cs_strlen(new_provid->prov) == 0)
415 NULLFREE(new_provid->provid);
416 NULLFREE(new_provid);
417 continue;
420 nr++;
422 if(provid_ptr)
424 provid_ptr->next = new_provid;
426 else
428 new_cfg_provid = new_provid;
430 provid_ptr = new_provid;
433 NULLFREE(token);
434 fclose(fp);
436 if(nr > 0)
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)))
443 return (1);
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);
455 struct s_client *cl;
456 for(cl = first_client->next; cl ; cl = cl->next)
457 { cl->last_providptr = NULL; }
459 struct s_provid *ptr, *nptr;
461 if(last_provid)
463 ptr = last_provid;
464 while(ptr) // cleanup old data:
466 add_garbage(ptr->provid);
467 nptr = ptr->next;
468 add_garbage(ptr);
469 ptr = nptr;
473 return (0);
476 int32_t init_srvid(void)
478 int8_t new_syntax = 1;
479 FILE *fp = open_config_file("oscam.srvid2");
480 if(!fp)
482 fp = open_config_file(cs_srid);
483 if(fp)
485 new_syntax = 0;
489 if(!fp)
491 fp = create_config_file("oscam.srvid2");
492 if(fp)
494 flush_config_file(fp, "oscam.srvid2");
497 return 0;
500 int32_t nr = 0, i, j;
501 char *payload, *saveptr1 = NULL, *saveptr2 = NULL, *token;
502 const char *tmp;
503 if(!cs_malloc(&token, MAXLINESIZE))
504 { return 0; }
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 };
511 struct timeb ts, te;
512 cs_ftime(&ts);
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;
520 uint32_t k;
521 uint32_t pos;
522 char *srvidasc, *prov;
523 tmp = trim(token);
525 if(tmp[0] == '#') { continue; }
526 if(cs_strlen(tmp) < 6) { continue; }
527 if(!(srvidasc = strchr(token, ':'))) { continue; }
528 if(!(payload = strchr(token, '|'))) { continue; }
529 *payload++ = '\0';
531 if(!cs_malloc(&srvid, sizeof(struct s_srvid)))
533 NULLFREE(token);
534 fclose(fp);
535 return (1);
538 char tmptxt[128];
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);
546 if(new_syntax)
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);
558 payload[0] = ' ';
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);
568 payload[k] = ' ';
570 else
572 break;
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);
581 pos = 0;
582 for(j = 0; j < len2; ++j) { pos += (uint8_t)ptr1[j]; }
583 pos = pos % 1024;
584 for(j = 0; j < used[pos]; ++j)
586 if(!strcmp(stringcache[pos][j], ptr1))
588 searchptr[i] = stringcache[pos][j];
589 break;
592 if(searchptr[i]) { continue; }
594 offset[i] = len;
595 cs_strncpy(tmptxt + len, trim(ptr1), sizeof(tmptxt) - len);
596 len += cs_strlen(ptr1) + 1;
599 char *tmpptr = NULL;
600 if(len > 0 && !cs_malloc(&tmpptr, len))
601 { continue; }
603 srvid->data = tmpptr;
604 if(len > 0) { memcpy(tmpptr, tmptxt, len); }
606 for(i = 0; i < 4; i++)
608 if(searchptr[i])
610 *ptrs[i] = searchptr[i];
611 continue;
613 if(offset[i] > -1)
615 *ptrs[i] = tmpptr + offset[i];
616 // store string in stringcache
617 if (*ptrs[i])
619 tmp = *ptrs[i];
620 len2 = cs_strlen(tmp);
622 else
624 cs_log("FIXME! len2!");
625 len2 = 0;
628 pos = 0;
629 for(j = 0; j < len2; ++j) { pos += (uint8_t)tmp[j]; }
630 if (pos > 0)
632 pos = pos % 1024;
634 if(used[pos] >= allocated[pos])
636 if(allocated[pos] == 0)
638 if(!cs_malloc(&stringcache[pos], 16 * sizeof(char *)))
639 { break; }
641 else
643 if(!cs_realloc(&stringcache[pos], (allocated[pos] + 16) * sizeof(char *)))
644 { break; }
646 allocated[pos] += 16;
648 if (tmp[0])
650 stringcache[pos][used[pos]] = tmp;
651 used[pos] += 1;
656 *srvidasc++ = '\0';
657 if(new_syntax)
658 { srvidtmp = dyn_word_atob(token) & 0xFFFF; }
659 else
660 { srvidtmp = dyn_word_atob(srvidasc) & 0xFFFF; }
662 if(srvidtmp < 0)
664 NULLFREE(tmpptr);
665 NULLFREE(srvid);
666 continue;
668 else
670 srvid->srvid = srvidtmp;
673 srvid->ncaid = 0;
674 for(i = 0, ptr1 = strtok_r(new_syntax ? srvidasc : token, ",", &saveptr1); (ptr1); ptr1 = strtok_r(NULL, ",", &saveptr1), i++)
676 srvid->ncaid++;
679 if(!cs_malloc(&srvid->caid, sizeof(struct s_srvid_caid) * srvid->ncaid))
681 NULLFREE(tmpptr);
682 NULLFREE(srvid);
683 return 0;
686 ptr1 = new_syntax ? srvidasc : token;
687 for(i = 0; i < srvid->ncaid; i++)
689 prov = strchr(ptr1,'@');
691 srvid->caid[i].nprovid = 0;
693 if(prov)
695 if(prov[1] != '\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);
707 NULLFREE(tmpptr);
708 NULLFREE(srvid);
709 return 0;
712 ptr2 = prov + 1;
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;
719 else
721 ptr2 = prov + 2;
724 prov[0] = '\0';
727 srvid->caid[i].caid = dyn_word_atob(ptr1) & 0xFFFF;
728 if(prov)
729 { ptr1 = ptr2; }
730 else
731 { ptr1 = ptr1 + cs_strlen(ptr1) + 1; }
734 nr++;
736 if(new_cfg_srvid[srvid->srvid >> 12])
737 { last_srvid[srvid->srvid >> 12]->next = srvid; }
738 else
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]); }
747 NULLFREE(token);
749 cs_ftime(&te);
750 int64_t load_time = comp_timeb(&te, &ts);
752 fclose(fp);
753 if(nr > 0)
755 cs_log("%d service-id's loaded in %"PRId64" ms", nr, load_time);
756 if(nr > 2000)
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);
770 struct s_client *cl;
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++)
778 ptr = last_srvid[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);
785 nptr = ptr->next;
786 add_garbage(ptr);
787 ptr = nptr;
791 return (0);
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;
800 FILE *fp;
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);
814 if(!fp)
815 { return 0; }
817 if(!cs_malloc(&token, MAXLINESIZE))
818 { return 0; }
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)
828 wrong_checksum = 0;
830 for(i = 0; i < 16; i += 4)
832 c = ((cw[i] + cw[i + 1] + cw[i + 2]) & 0xff);
833 if(cw[i + 3] != c)
835 wrong_checksum = 1;
839 if(wrong_checksum)
841 cs_log("skipping fake cw %s because of wrong checksum!", cw_string);
843 else
845 idx = ((cw[0] & 0xF) << 4) | (cw[8] & 0xF);
846 alloccount[idx]++;
847 have_fakecw = 1;
850 else
852 cs_log("skipping fake cw %s because it contains invalid characters!", cw_string);
855 else
857 cs_log("skipping fake cw %s because of wrong length (%u != 32)!", cw_string, (uint32_t)cs_strlen(cw_string));
862 if(!have_fakecw)
864 NULLFREE(token);
865 fclose(fp);
866 return 0;
869 for(i = 0; i < 0x100; i++)
871 if(alloccount[i] && !cs_malloc(&cfg.fakecws[i].data, sizeof(struct s_cw)*alloccount[i]))
873 alloccount[i] = 0;
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)
887 wrong_checksum = 0;
889 for(i = 0; i < 16; i += 4)
891 c = ((cw[i] + cw[i + 1] + cw[i + 2]) & 0xff);
892 if(cw[i + 3] != c)
894 wrong_checksum = 1;
898 if(!wrong_checksum)
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);
905 count[idx]++;
906 nr++;
914 NULLFREE(token);
915 fclose(fp);
917 if(nr > 0)
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])
941 tmp = count[i];
942 count[i] = count[j];
943 count[j] = tmp;
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);
952 return 0;
955 static struct s_rlimit *ratelimit_read_int(void)
957 FILE *fp = open_config_file(cs_ratelimit);
958 if(!fp)
959 { return NULL; }
960 char token[1024], str1[1024];
961 int32_t i, ret, count = 0;
962 struct s_rlimit *new_rlimit = NULL, *entry, *last = NULL;
963 uint32_t line = 0;
965 while(fgets(token, sizeof(token), fp))
967 line++;
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);
977 token[i + 1] = '0';
979 if(token[i] == '#' || token[i] == '/')
981 token[i] = '\0';
982 break;
986 caid = 0;
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);
991 if(ret < 1) {
992 continue;
995 if (!cs_strncat(str1, ",", sizeof(str1))) {
996 return new_rlimit;
999 if(!cs_malloc(&entry, sizeof(struct s_rlimit)))
1001 fclose(fp);
1002 return new_rlimit;
1005 count++;
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);
1019 if(!new_rlimit)
1021 new_rlimit = entry;
1022 last = new_rlimit;
1024 else
1026 last->next = entry;
1027 last = entry;
1031 if(count)
1032 { cs_log("%d entries read from %s", count, cs_ratelimit); }
1034 fclose(fp);
1036 return new_rlimit;
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();
1047 while(old_list)
1049 entry = old_list->next;
1050 NULLFREE(old_list);
1051 old_list = entry;
1055 struct ecmrl get_ratelimit(ECM_REQUEST *er)
1058 struct ecmrl tmp;
1059 memset(&tmp, 0, sizeof(tmp));
1060 if(!cfg.ratelimit_list) { return tmp; }
1061 struct s_rlimit *entry = cfg.ratelimit_list;
1062 while(entry)
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))
1066 break;
1068 entry = entry->next;
1071 if(entry) { tmp = entry->rl; }
1073 return (tmp);
1076 int32_t init_tierid(void)
1078 FILE *fp = open_config_file(cs_trid);
1079 if(!fp)
1080 { return 0; }
1082 int32_t nr;
1083 char *payload, *saveptr1 = NULL, *token;
1084 if(!cs_malloc(&token, MAXLINESIZE))
1085 { return 0; }
1086 static struct s_tierid *tierid = NULL, *new_cfg_tierid = NULL;
1088 nr = 0;
1089 while(fgets(token, MAXLINESIZE, fp))
1091 void *ptr;
1092 char *tmp, *tieridasc;
1093 tmp = trim(token);
1095 if(tmp[0] == '#') { continue; }
1096 if(cs_strlen(tmp) < 6) { continue; }
1097 if(!(payload = strchr(token, '|'))) { continue; }
1098 if(!(tieridasc = strchr(token, ':'))) { continue; }
1099 *payload++ = '\0';
1101 if(!cs_malloc(&ptr, sizeof(struct s_tierid)))
1103 NULLFREE(token);
1104 fclose(fp);
1105 return (1);
1107 if(tierid)
1108 { tierid->next = ptr; }
1109 else
1110 { new_cfg_tierid = ptr; }
1112 tierid = ptr;
1114 int32_t i;
1115 char *ptr1 = strtok_r(payload, "|", &saveptr1);
1116 if(ptr1)
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 );
1123 tierid->ncaid = 0;
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);
1130 nr++;
1132 NULLFREE(token);
1133 fclose(fp);
1134 if(nr > 0)
1135 { cs_log("%d tier-id's loaded", nr); }
1136 cs_writelock(__func__, &config_lock);
1137 // reload function:
1138 tierid = cfg.tierid;
1139 cfg.tierid = new_cfg_tierid;
1140 struct s_tierid *ptr;
1141 while(tierid)
1143 ptr = tierid->next;
1144 NULLFREE(tierid);
1145 tierid = ptr;
1147 cs_writeunlock(__func__, &config_lock);
1149 return (0);
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)
1164 *line = -1;
1165 if(!cfg.global_whitelist)
1166 { return 1; }
1168 struct s_global_whitelist *entry;
1170 // check mapping:
1171 if(cfg.global_whitelist_use_m)
1173 entry = cfg.global_whitelist;
1174 while(entry)
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;
1183 break;
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;
1194 while(entry)
1196 if(entry->type == 'l')
1198 if(match_whitelist(er, entry))
1200 *line = entry->line;
1201 return 1;
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!
1216 { return 0; }
1219 entry = cfg.global_whitelist;
1220 while(entry)
1222 if(match_whitelist(er, entry))
1224 *line = entry->line;
1225 if(entry->type == 'w')
1226 { return 1; }
1227 else if(entry->type == 'i')
1228 { return 0; }
1230 entry = entry->next;
1232 return 0;
1235 //Format:
1236 //Whitelist-Entry:
1237 //w:caid:prov:srvid:pid:chid:ecmlen
1238 //Ignore-Entry:
1239 //i:caid:prov:srvid:pid:chid:ecmlen
1240 //ECM len check - Entry:
1241 //l:caid:prov:srvid:pid:chid:ecmlen
1243 //Mapping:
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);
1249 if(!fp)
1250 { return NULL; }
1252 char token[1024], str1[1024];
1253 uint8_t type;
1254 int32_t i, ret, count = 0;
1255 struct s_global_whitelist *new_whitelist = NULL, *entry, *last = NULL;
1256 uint32_t line = 0;
1258 cfg.global_whitelist_use_l = 0;
1259 cfg.global_whitelist_use_m = 0;
1261 while(fgets(token, sizeof(token), fp))
1263 line++;
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);
1273 token[i + 1] = '0';
1275 if(token[i] == '#' || token[i] == '/')
1277 token[i] = '\0';
1278 break;
1282 type = 'w';
1283 caid = 0;
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);
1291 //w=whitelist
1292 //i=ignore
1293 //l=len-check
1294 //m=map caid/prov
1295 if(ret < 1 || (type != 'w' && type != 'i' && type != 'l' && type != 'm'))
1296 { continue; }
1298 if(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);
1304 continue;
1306 str1[0] = 0;
1307 cfg.global_whitelist_use_m = 1;
1310 if (!cs_strncat(str1, ",", sizeof(str1))) {
1311 return new_whitelist;
1314 char *p = str1, *p2 = str1;
1316 while(*p)
1318 if(*p == ',')
1320 *p = 0;
1321 ecmlen = 0;
1322 sscanf(p2, "%4x", &ecmlen);
1324 if(!cs_malloc(&entry, sizeof(struct s_global_whitelist)))
1326 fclose(fp);
1327 return new_whitelist;
1330 count++;
1331 entry->line = line;
1332 entry->type = type;
1333 entry->caid = caid;
1334 entry->provid = provid;
1335 entry->srvid = srvid;
1336 entry->pid = pid;
1337 entry->chid = chid;
1338 entry->ecmlen = ecmlen;
1339 entry->mapcaid = mapcaid;
1340 entry->mapprovid = mapprovid;
1341 if(entry->type == 'l')
1342 { cfg.global_whitelist_use_l = 1; }
1344 if(type == 'm')
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);
1347 else
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);
1351 if(!new_whitelist)
1353 new_whitelist = entry;
1354 last = new_whitelist;
1356 else
1358 last->next = entry;
1359 last = entry;
1362 p2 = p + 1;
1364 p++;
1368 if(count)
1369 { cs_log("%d entries read from %s", count, cs_whitelist); }
1371 fclose(fp);
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();
1383 while(old_list)
1385 entry = old_list->next;
1386 NULLFREE(old_list);
1387 old_list = entry;
1391 #ifdef MODULE_SERIAL
1392 static struct s_twin *twin_read_int(void)
1394 FILE *fp = open_config_file(cs_twin);
1395 if(!fp)
1396 { return NULL; }
1397 char token[1024], str1[1024];
1398 int32_t i, ret, count = 0;
1399 struct s_twin *new_twin = NULL, *entry, *last = NULL;
1400 uint32_t line = 0;
1402 while(fgets(token, sizeof(token), fp))
1404 line++;
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);
1414 token[i + 1] = '0';
1416 if(token[i] == '#' || token[i] == '/' || token[i] == '"')
1418 token[i] = '\0';
1419 break;
1423 caid = 0;
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, &deg, &freq, &srvid);
1429 if(ret < 1) { continue; }
1431 //snprintf(hdeg, 4, "%x", deg);
1432 //sscanf(hdeg, "%4x", &deg);
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))) {
1438 return new_twin;
1441 if(!cs_malloc(&entry, sizeof(struct s_twin)))
1443 fclose(fp);
1444 return new_twin;
1447 count++;
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);
1457 if(!new_twin)
1459 new_twin = entry;
1460 last = new_twin;
1462 else
1464 last->next = entry;
1465 last = entry;
1469 if(count)
1470 { cs_log("%d entries read from %s", count, cs_twin); }
1472 fclose(fp);
1474 return new_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();
1485 while(old_list)
1487 entry = old_list->next;
1488 free(old_list);
1489 old_list = entry;
1493 struct ecmtw get_twin(ECM_REQUEST *er)
1495 struct ecmtw tmp;
1496 memset(&tmp, 0, sizeof(tmp));
1497 if(!cfg.twin_list)
1499 cs_log("twin_list not found!");
1500 return tmp;
1502 struct s_twin *entry = cfg.twin_list;
1503 while(entry)
1505 if(entry->tw.caid == er->caid && entry->tw.provid == er->prid && entry->tw.srvid == er->srvid)
1507 break;
1509 entry = entry->next;
1512 if(entry) { tmp = entry->tw; }
1514 return (tmp);
1516 #endif