revert breaks some stupid old compilers
[oscam.git] / oscam-config.c
blobe75f3e08b52925b867f47223916289529ddc01c5
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 extern uint16_t len4caid[256];
18 #define cs_srid "oscam.srvid"
19 #define cs_ratelimit "oscam.ratelimit"
20 #define cs_trid "oscam.tiers"
21 #define cs_l4ca "oscam.guess"
22 #define cs_sidt "oscam.services"
23 #define cs_whitelist "oscam.whitelist"
24 #define cs_provid "oscam.provid"
25 #define cs_fakecws "oscam.fakecws"
26 #define cs_twin "oscam.twin"
28 uint32_t cfg_sidtab_generation = 1;
30 extern char cs_confdir[];
32 char *get_config_filename(char *dest, size_t destlen, const char *filename)
34 // cs_confdir is always terminated with /
35 snprintf(dest, destlen, "%s%s", cs_confdir, filename);
36 return dest;
39 int32_t write_services(void)
41 int32_t i;
42 struct s_sidtab *sidtab = cfg.sidtab;
43 char *ptr;
44 FILE *f = create_config_file(cs_sidt);
45 if(!f)
46 { return 1; }
48 while(sidtab != NULL)
50 ptr = sidtab->label;
51 while(*ptr)
53 if(*ptr == ' ') { *ptr = '_'; }
54 ptr++;
56 fprintf(f, "[%s]\n", sidtab->label);
57 fprintf_conf(f, "caid", "%s", ""); // it should not have \n at the end
58 for(i = 0; i < sidtab->num_caid; i++)
60 if(i == 0) { fprintf(f, "%04X", sidtab->caid[i]); }
61 else { fprintf(f, ",%04X", sidtab->caid[i]); }
63 fputc((int)'\n', f);
64 fprintf_conf(f, "provid", "%s", ""); // it should not have \n at the end
65 for(i = 0; i < sidtab->num_provid; i++)
67 if(i == 0) { fprintf(f, "%06X", sidtab->provid[i]); }
68 else { fprintf(f, ",%06X", sidtab->provid[i]); }
70 fputc((int)'\n', f);
71 fprintf_conf(f, "srvid", "%s", ""); // it should not have \n at the end
72 for(i = 0; i < sidtab->num_srvid; i++)
74 if(i == 0) { fprintf(f, "%04X", sidtab->srvid[i]); }
75 else { fprintf(f, ",%04X", sidtab->srvid[i]); }
77 fprintf(f, "\n\n");
78 sidtab = sidtab->next;
81 return flush_config_file(f, cs_sidt);
84 void free_sidtab(struct s_sidtab *ptr)
86 if(!ptr) { return; }
87 add_garbage(ptr->caid); //no need to check on NULL first, freeing NULL doesnt do anything
88 add_garbage(ptr->provid);
89 add_garbage(ptr->srvid);
90 add_garbage(ptr);
93 static void chk_entry4sidtab(char *value, struct s_sidtab *sidtab, int32_t what)
95 int32_t i, b;
96 char *ptr, *saveptr1 = NULL;
97 uint16_t *slist = (uint16_t *) 0;
98 uint32_t *llist = (uint32_t *) 0;
99 uint32_t caid;
100 char buf[strlen(value) + 1];
101 cs_strncpy(buf, value, sizeof(buf));
102 b = (what == 1) ? sizeof(uint32_t) : sizeof(uint16_t);
103 for(i = 0, ptr = strtok_r(value, ",", &saveptr1); ptr; ptr = strtok_r(NULL, ",", &saveptr1))
105 caid = a2i(ptr, b);
106 if(!errno) { i++; }
108 //if (!i) return(0);
109 if(b == sizeof(uint16_t))
111 if(!cs_malloc(&slist, i * sizeof(uint16_t))) { return; }
113 else
115 if(!cs_malloc(&llist, i * sizeof(uint32_t))) { return; }
117 cs_strncpy(value, buf, sizeof(buf));
118 for(i = 0, ptr = strtok_r(value, ",", &saveptr1); ptr; ptr = strtok_r(NULL, ",", &saveptr1))
120 caid = a2i(ptr, b);
121 if(errno) { continue; }
122 if(b == sizeof(uint16_t))
123 { slist[i++] = (uint16_t) caid; }
124 else
125 { llist[i++] = caid; }
127 switch(what)
129 case 0:
130 add_garbage(sidtab->caid);
131 sidtab->caid = slist;
132 sidtab->num_caid = i;
133 break;
134 case 1:
135 add_garbage(sidtab->provid);
136 sidtab->provid = llist;
137 sidtab->num_provid = i;
138 break;
139 case 2:
140 add_garbage(sidtab->srvid);
141 sidtab->srvid = slist;
142 sidtab->num_srvid = i;
143 break;
147 void chk_sidtab(char *token, char *value, struct s_sidtab *sidtab)
149 if(!strcmp(token, "caid"))
151 chk_entry4sidtab(value, sidtab, 0);
152 return;
154 if(!strcmp(token, "provid"))
156 chk_entry4sidtab(value, sidtab, 1);
157 return;
159 if(!strcmp(token, "ident"))
161 chk_entry4sidtab(value, sidtab, 1);
162 return;
164 if(!strcmp(token, "srvid"))
166 chk_entry4sidtab(value, sidtab, 2);
167 return;
169 if(token[0] != '#')
170 { fprintf(stderr, "Warning: keyword '%s' in sidtab section not recognized\n", token); }
173 void init_free_sidtab(void)
175 struct s_sidtab *nxt, *ptr = cfg.sidtab;
176 while(ptr)
178 nxt = ptr->next;
179 free_sidtab(ptr);
180 ptr = nxt;
182 cfg.sidtab = NULL;
183 ++cfg_sidtab_generation;
186 //#define DEBUG_SIDTAB 1
187 #ifdef DEBUG_SIDTAB
188 static void show_sidtab(struct s_sidtab *sidtab)
190 for(; sidtab; sidtab = sidtab->next)
192 int32_t i;
193 char buf[1024];
194 char *saveptr = buf;
195 cs_log("label=%s", sidtab->label);
196 snprintf(buf, sizeof(buf), "caid(%d)=", sidtab->num_caid);
197 for(i = 0; i < sidtab->num_caid; i++)
198 { snprintf(buf + strlen(buf), 1024 - (buf - saveptr), "%04X ", sidtab->caid[i]); }
199 cs_log("%s", buf);
200 snprintf(buf, sizeof(buf), "provider(%d)=", sidtab->num_provid);
201 for(i = 0; i < sidtab->num_provid; i++)
202 { snprintf(buf + strlen(buf), 1024 - (buf - saveptr), "%08X ", sidtab->provid[i]); }
203 cs_log("%s", buf);
204 snprintf(buf, sizeof(buf), "services(%d)=", sidtab->num_srvid);
205 for(i = 0; i < sidtab->num_srvid; i++)
206 { snprintf(buf + strlen(buf), 1024 - (buf - saveptr), "%04X ", sidtab->srvid[i]); }
207 cs_log("%s", buf);
210 #else
211 static void show_sidtab(struct s_sidtab *UNUSED(sidtab)) { }
212 #endif
214 int32_t init_sidtab(void)
216 FILE *fp = open_config_file(cs_sidt);
217 if(!fp)
218 { return 1; }
220 int32_t nr, nro, nrr;
221 char *value, *token;
222 if(!cs_malloc(&token, MAXLINESIZE))
223 { return 1; }
224 struct s_sidtab *ptr;
225 struct s_sidtab *sidtab = (struct s_sidtab *)0;
227 for(nro = 0, ptr = cfg.sidtab; ptr; nro++)
229 struct s_sidtab *ptr_next;
230 ptr_next = ptr->next;
231 free_sidtab(ptr);
232 ptr = ptr_next;
234 nr = 0;
235 nrr = 0;
236 while(fgets(token, MAXLINESIZE, fp))
238 int32_t l;
239 if((l = strlen(trim(token))) < 3) { continue; }
240 if((token[0] == '[') && (token[l - 1] == ']'))
242 token[l - 1] = 0;
243 if(nr > MAX_SIDBITS)
245 fprintf(stderr, "Warning: Service No.%d - '%s' ignored. Max allowed Services %d\n", nr, strtolower(token + 1), MAX_SIDBITS);
246 nr++;
247 nrr++;
249 else
251 if(!cs_malloc(&ptr, sizeof(struct s_sidtab)))
253 NULLFREE(token);
254 return (1);
256 if(sidtab)
257 { sidtab->next = ptr; }
258 else
259 { cfg.sidtab = ptr; }
260 sidtab = ptr;
261 nr++;
262 cs_strncpy(sidtab->label, strtolower(token + 1), sizeof(sidtab->label));
263 continue;
266 if(!sidtab) { continue; }
267 if(!(value = strchr(token, '='))) { continue; }
268 *value++ = '\0';
269 chk_sidtab(trim(strtolower(token)), trim(strtolower(value)), sidtab);
271 NULLFREE(token);
272 fclose(fp);
274 show_sidtab(cfg.sidtab);
275 ++cfg_sidtab_generation;
276 cs_log("services reloaded: %d services freed, %d services loaded, rejected %d", nro, nr, nrr);
277 return (0);
280 int32_t init_provid(void)
282 FILE *fp = open_config_file(cs_provid);
283 if(!fp)
284 { return 0; }
286 int32_t nr;
287 char *payload, *saveptr1 = NULL, *token;
288 if(!cs_malloc(&token, MAXLINESIZE))
289 { return 0; }
290 struct s_provid *provid_ptr = NULL;
291 struct s_provid *new_cfg_provid = NULL, *last_provid;
293 nr = 0;
294 while(fgets(token, MAXLINESIZE, fp))
296 int32_t i, l;
297 struct s_provid *new_provid = NULL;
298 char *tmp, *ptr1;
300 tmp = trim(token);
302 if(tmp[0] == '#') { continue; }
303 if((l = strlen(tmp)) < 11) { continue; }
304 if(!(payload = strchr(token, '|'))) { continue; }
306 *payload++ = '\0';
308 if(!cs_malloc(&new_provid, sizeof(struct s_provid)))
310 NULLFREE(token);
311 fclose(fp);
312 return (1);
315 new_provid->nprovid = 0;
316 for(i = 0, ptr1 = strtok_r(token, ":@", &saveptr1); ptr1; ptr1 = strtok_r(NULL, ":@", &saveptr1), i++)
318 if(i==0)
320 new_provid->caid = a2i(ptr1, 3);
321 continue;
324 new_provid->nprovid++;
327 if(!cs_malloc(&new_provid->provid, sizeof(uint32_t) * new_provid->nprovid))
329 NULLFREE(new_provid);
330 NULLFREE(token);
331 fclose(fp);
332 return (1);
335 ptr1 = token + strlen(token) + 1;
336 for(i = 0; i < new_provid->nprovid ; i++)
338 new_provid->provid[i] = a2i(ptr1, 3);
340 ptr1 = ptr1 + strlen(ptr1) + 1;
343 for(i = 0, ptr1 = strtok_r(payload, "|", &saveptr1); ptr1; ptr1 = strtok_r(NULL, "|", &saveptr1), i++)
345 switch(i)
347 case 0:
348 cs_strncpy(new_provid->prov, trim(ptr1), sizeof(new_provid->prov));
349 break;
350 case 1:
351 cs_strncpy(new_provid->sat, trim(ptr1), sizeof(new_provid->sat));
352 break;
353 case 2:
354 cs_strncpy(new_provid->lang, trim(ptr1), sizeof(new_provid->lang));
355 break;
359 if(strlen(new_provid->prov) == 0)
361 NULLFREE(new_provid->provid);
362 NULLFREE(new_provid);
363 continue;
366 nr++;
368 if(provid_ptr)
370 provid_ptr->next = new_provid;
372 else
374 new_cfg_provid = new_provid;
376 provid_ptr = new_provid;
379 NULLFREE(token);
380 fclose(fp);
382 if(nr > 0)
383 { cs_log("%d provid's loaded", nr); }
385 if(new_cfg_provid == NULL)
387 if(!cs_malloc(&new_cfg_provid, sizeof(struct s_provid)))
389 return (1);
393 cs_writelock(__func__, &config_lock);
395 //this allows reloading of provids, so cleanup of old data is needed:
396 last_provid = cfg.provid; //old data
397 cfg.provid = new_cfg_provid; //assign after loading, so everything is in memory
399 cs_writeunlock(__func__, &config_lock);
401 struct s_client *cl;
402 for(cl = first_client->next; cl ; cl = cl->next)
403 { cl->last_providptr = NULL; }
405 struct s_provid *ptr, *nptr;
407 if(last_provid)
409 ptr = last_provid;
410 while(ptr) //cleanup old data:
412 add_garbage(ptr->provid);
413 nptr = ptr->next;
414 add_garbage(ptr);
415 ptr = nptr;
419 return (0);
422 int32_t init_srvid(void)
424 int8_t new_syntax = 1;
425 FILE *fp = open_config_file("oscam.srvid2");
426 if(!fp)
428 fp = open_config_file(cs_srid);
429 if(fp)
431 new_syntax = 0;
435 if(!fp)
437 fp = create_config_file("oscam.srvid2");
438 if(fp)
440 flush_config_file(fp, "oscam.srvid2");
443 return 0;
446 int32_t nr = 0, i, j;
447 char *payload, *saveptr1 = NULL, *saveptr2 = NULL, *token;
448 const char *tmp;
449 if(!cs_malloc(&token, MAXLINESIZE))
450 { return 0; }
451 struct s_srvid *srvid = NULL, *new_cfg_srvid[16], *last_srvid[16];
452 // A cache for strings within srvids. A checksum is calculated which is the start point in the array (some kind of primitive hash algo).
453 // From this point, a sequential search is done. This greatly reduces the amount of string comparisons.
454 const char **stringcache[1024];
455 int32_t allocated[1024] = { 0 };
456 int32_t used[1024] = { 0 };
457 struct timeb ts, te;
458 cs_ftime(&ts);
460 memset(last_srvid, 0, sizeof(last_srvid));
461 memset(new_cfg_srvid, 0, sizeof(new_cfg_srvid));
463 while(fgets(token, MAXLINESIZE, fp))
465 int32_t l, len = 0, len2, srvidtmp;
466 uint32_t k;
467 uint32_t pos;
468 char *srvidasc, *prov;
469 tmp = trim(token);
471 if(tmp[0] == '#') { continue; }
472 if((l = strlen(tmp)) < 6) { continue; }
473 if(!(srvidasc = strchr(token, ':'))) { continue; }
474 if(!(payload = strchr(token, '|'))) { continue; }
475 *payload++ = '\0';
477 if(!cs_malloc(&srvid, sizeof(struct s_srvid)))
479 NULLFREE(token);
480 fclose(fp);
481 return (1);
484 char tmptxt[128];
486 int32_t offset[4] = { -1, -1, -1, -1 };
487 char *ptr1 = NULL, *ptr2 = NULL;
488 const char *searchptr[4] = { NULL, NULL, NULL, NULL };
489 const char **ptrs[4] = { &srvid->prov, &srvid->name, &srvid->type, &srvid->desc };
490 uint32_t max_payload_length = MAXLINESIZE - (payload - token);
492 if(new_syntax)
494 ptrs[0] = &srvid->name;
495 ptrs[1] = &srvid->type;
496 ptrs[2] = &srvid->desc;
497 ptrs[3] = &srvid->prov;
500 // allow empty strings as "||"
501 if(payload[0] == '|' && (strlen(payload)+2 < max_payload_length))
503 memmove(payload+1, payload, strlen(payload)+1);
504 payload[0] = ' ';
507 for(k=1; ((k < max_payload_length) && (payload[k] != '\0')); k++)
509 if(payload[k-1] == '|' && payload[k] == '|')
511 if(strlen(payload+k)+2 < max_payload_length-k)
513 memmove(payload+k+1, payload+k, strlen(payload+k)+1);
514 payload[k] = ' ';
516 else
518 break;
523 for(i = 0, ptr1 = strtok_r(payload, "|", &saveptr1); ptr1 && (i < 4) ; ptr1 = strtok_r(NULL, "|", &saveptr1), ++i)
525 // check if string is in cache
526 len2 = strlen(ptr1);
527 pos = 0;
528 for(j = 0; j < len2; ++j) { pos += (uint8_t)ptr1[j]; }
529 pos = pos % 1024;
530 for(j = 0; j < used[pos]; ++j)
532 if(!strcmp(stringcache[pos][j], ptr1))
534 searchptr[i] = stringcache[pos][j];
535 break;
538 if(searchptr[i]) { continue; }
540 offset[i] = len;
541 cs_strncpy(tmptxt + len, trim(ptr1), sizeof(tmptxt) - len);
542 len += strlen(ptr1) + 1;
545 char *tmpptr = NULL;
546 if(len > 0 && !cs_malloc(&tmpptr, len))
547 { continue; }
549 srvid->data = tmpptr;
550 if(len > 0) { memcpy(tmpptr, tmptxt, len); }
552 for(i = 0; i < 4; i++)
554 if(searchptr[i])
556 *ptrs[i] = searchptr[i];
557 continue;
559 if(offset[i] > -1)
561 *ptrs[i] = tmpptr + offset[i];
562 // store string in stringcache
563 tmp = *ptrs[i];
564 len2 = strlen(tmp);
565 pos = 0;
566 for(j = 0; j < len2; ++j) { pos += (uint8_t)tmp[j]; }
567 pos = pos % 1024;
568 if(used[pos] >= allocated[pos])
570 if(allocated[pos] == 0)
572 if(!cs_malloc(&stringcache[pos], 16 * sizeof(char *)))
573 { break; }
575 else
577 if(!cs_realloc(&stringcache[pos], (allocated[pos] + 16) * sizeof(char *)))
578 { break; }
580 allocated[pos] += 16;
582 stringcache[pos][used[pos]] = tmp;
583 used[pos] += 1;
587 *srvidasc++ = '\0';
588 if(new_syntax)
589 { srvidtmp = dyn_word_atob(token) & 0xFFFF; }
590 else
591 { srvidtmp = dyn_word_atob(srvidasc) & 0xFFFF; }
593 if(srvidtmp < 0)
595 NULLFREE(tmpptr);
596 NULLFREE(srvid);
597 continue;
599 else
601 srvid->srvid = srvidtmp;
604 srvid->ncaid = 0;
605 for(i = 0, ptr1 = strtok_r(new_syntax ? srvidasc : token, ",", &saveptr1); (ptr1); ptr1 = strtok_r(NULL, ",", &saveptr1), i++)
607 srvid->ncaid++;
610 if(!cs_malloc(&srvid->caid, sizeof(struct s_srvid_caid) * srvid->ncaid))
612 NULLFREE(tmpptr);
613 NULLFREE(srvid);
614 return 0;
617 ptr1 = new_syntax ? srvidasc : token;
618 for(i = 0; i < srvid->ncaid; i++)
620 prov = strchr(ptr1,'@');
622 srvid->caid[i].nprovid = 0;
624 if(prov)
626 if(prov[1] != '\0')
628 for(j = 0, ptr2 = strtok_r(prov+1, "@", &saveptr2); (ptr2); ptr2 = strtok_r(NULL, "@", &saveptr2), j++)
630 srvid->caid[i].nprovid++;
633 if(!cs_malloc(&srvid->caid[i].provid, sizeof(uint32_t) * srvid->caid[i].nprovid))
635 for(j = 0; j < i; j++)
636 { NULLFREE(srvid->caid[j].provid); }
637 NULLFREE(srvid->caid);
638 NULLFREE(tmpptr);
639 NULLFREE(srvid);
640 return 0;
643 ptr2 = prov+1;
644 for(j = 0; j < srvid->caid[i].nprovid; j++)
646 srvid->caid[i].provid[j] = dyn_word_atob(ptr2) & 0xFFFFFF;
647 ptr2 = ptr2 + strlen(ptr2) + 1;
650 else
652 ptr2 = prov+2;
655 prov[0] = '\0';
658 srvid->caid[i].caid = dyn_word_atob(ptr1) & 0xFFFF;
659 if(prov)
660 { ptr1 = ptr2; }
661 else
662 { ptr1 = ptr1 + strlen(ptr1) + 1; }
665 nr++;
667 if(new_cfg_srvid[srvid->srvid >> 12])
668 { last_srvid[srvid->srvid >> 12]->next = srvid; }
669 else
670 { new_cfg_srvid[srvid->srvid >> 12] = srvid; }
672 last_srvid[srvid->srvid >> 12] = srvid;
674 for(i = 0; i < 1024; ++i)
676 if(allocated[i] > 0) { NULLFREE(stringcache[i]); }
678 NULLFREE(token);
680 cs_ftime(&te);
681 int64_t load_time = comp_timeb(&te, &ts);
683 fclose(fp);
684 if(nr > 0)
686 cs_log("%d service-id's loaded in %"PRId64" ms", nr, load_time);
687 if(nr > 2000)
689 cs_log("WARNING: You risk high CPU load and high ECM times with more than 2000 service-id's!");
690 cs_log("HINT: --> use optimized lists from http://www.streamboard.tv/wiki/Srvid");
694 cs_writelock(__func__, &config_lock);
695 //this allows reloading of srvids, so cleanup of old data is needed:
696 memcpy(last_srvid, cfg.srvid, sizeof(last_srvid)); //old data
697 memcpy(cfg.srvid, new_cfg_srvid, sizeof(last_srvid)); //assign after loading, so everything is in memory
699 cs_writeunlock(__func__, &config_lock);
701 struct s_client *cl;
702 for(cl = first_client->next; cl ; cl = cl->next)
703 { cl->last_srvidptr = NULL; }
705 struct s_srvid *ptr, *nptr;
707 for(i = 0; i < 16; i++)
709 ptr = last_srvid[i];
710 while(ptr) //cleanup old data:
712 for(j = 0; j < ptr->ncaid; j++)
713 { add_garbage(ptr->caid[j].provid); }
714 add_garbage(ptr->caid);
715 add_garbage(ptr->data);
716 nptr = ptr->next;
717 add_garbage(ptr);
718 ptr = nptr;
722 return (0);
725 int32_t init_fakecws(void)
727 int32_t nr = 0, i, j, idx;
728 uint32_t alloccount[0x100], count[0x100], tmp, max_compares = 0, average_compares = 0;
729 char *token, cw_string[64];
730 uint8_t cw[16], wrong_checksum, c, have_fakecw = 0;
731 FILE *fp;
733 memset(alloccount, 0, sizeof(count));
734 memset(count, 0, sizeof(alloccount));
736 cs_writelock(__func__, &config_lock);
737 for(i=0; i<0x100; i++)
739 cfg.fakecws[i].count = 0;
740 NULLFREE(cfg.fakecws[i].data);
742 cs_writeunlock(__func__, &config_lock);
744 fp = open_config_file(cs_fakecws);
745 if(!fp)
746 { return 0; }
748 if(!cs_malloc(&token, MAXLINESIZE))
749 { return 0; }
751 while(fgets(token, MAXLINESIZE, fp))
753 if(sscanf(token, " %62s ", cw_string) == 1)
755 if(strlen(cw_string) == 32)
757 if(cs_atob(cw, cw_string, 16) == 16)
759 wrong_checksum = 0;
761 for(i = 0; i < 16; i += 4)
763 c = ((cw[i] + cw[i + 1] + cw[i + 2]) & 0xff);
764 if(cw[i + 3] != c)
766 wrong_checksum = 1;
770 if(wrong_checksum)
772 cs_log("skipping fake cw %s because of wrong checksum!", cw_string);
774 else
776 idx = ((cw[0]&0xF)<<4) | (cw[8]&0xF);
777 alloccount[idx]++;
778 have_fakecw = 1;
781 else
783 cs_log("skipping fake cw %s because it contains invalid characters!", cw_string);
786 else
788 cs_log("skipping fake cw %s because of wrong length (%u != 32)!", cw_string, (uint32_t)strlen(cw_string));
793 if(!have_fakecw)
795 NULLFREE(token);
796 fclose(fp);
797 return 0;
800 for(i=0; i<0x100; i++)
802 if(alloccount[i] && !cs_malloc(&cfg.fakecws[i].data, sizeof(struct s_cw)*alloccount[i]))
804 alloccount[i] = 0;
808 fseek(fp, 0, SEEK_SET);
810 while(fgets(token, MAXLINESIZE, fp))
812 if(sscanf(token, " %62s ", cw_string) == 1)
814 if(strlen(cw_string) == 32)
816 if(cs_atob(cw, cw_string, 16) == 16)
818 wrong_checksum = 0;
820 for(i = 0; i < 16; i += 4)
822 c = ((cw[i] + cw[i + 1] + cw[i + 2]) & 0xff);
823 if(cw[i + 3] != c)
825 wrong_checksum = 1;
829 if(!wrong_checksum)
831 idx = ((cw[0]&0xF)<<4) | (cw[8]&0xF);
833 if(count[idx] < alloccount[idx])
835 memcpy(cfg.fakecws[idx].data[count[idx]].cw, cw, 16);
836 count[idx]++;
837 nr++;
845 NULLFREE(token);
846 fclose(fp);
848 if(nr > 0)
849 { cs_log("%d fakecws's loaded", nr); }
852 cs_writelock(__func__, &config_lock);
853 for(i=0; i<0x100; i++)
855 cfg.fakecws[i].count = count[i];
857 cs_writeunlock(__func__, &config_lock);
860 for(i=0; i<0x100; i++)
862 if(count[i] > max_compares)
863 { max_compares = count[i]; }
866 for(i=0; i<(0x100-1); i++) {
867 for(j=i+1; j<0x100; j++) {
868 if(count[j] < count[i]) {
869 tmp = count[i];
870 count[i] = count[j];
871 count[j] = tmp;
875 average_compares = ((count[0x100/2] + count[0x100/2 - 1]) / 2);
878 cs_log("max %d fakecw compares required, on average: %d compares", max_compares, average_compares);
880 return 0;
883 static struct s_rlimit *ratelimit_read_int(void)
885 FILE *fp = open_config_file(cs_ratelimit);
886 if(!fp)
887 { return NULL; }
888 char token[1024], str1[1024];
889 int32_t i, ret, count = 0;
890 struct s_rlimit *new_rlimit = NULL, *entry, *last = NULL;
891 uint32_t line = 0;
893 while(fgets(token, sizeof(token), fp))
895 line++;
896 if(strlen(token) <= 1) { continue; }
897 if(token[0] == '#' || token[0] == '/') { continue; }
898 if(strlen(token) > 1024) { continue; }
900 for(i = 0; i < (int)strlen(token); i++)
902 if((token[i] == ':' || token[i] == ' ') && token[i + 1] == ':')
904 memmove(token + i + 2, token + i + 1, strlen(token) - i + 1);
905 token[i + 1] = '0';
907 if(token[i] == '#' || token[i] == '/')
909 token[i] = '\0';
910 break;
914 uint32_t caid = 0, provid = 0, srvid = 0, chid = 0, ratelimitecm = 0, ratelimittime = 0, srvidholdtime = 0;
915 memset(str1, 0, sizeof(str1));
917 ret = sscanf(token, "%4x:%6x:%4x:%4x:%d:%d:%d:%1023s", &caid, &provid, &srvid, &chid, &ratelimitecm, &ratelimittime, &srvidholdtime, str1);
918 if(ret < 1) { continue; }
919 strncat(str1, ",", sizeof(str1) - strlen(str1) - 1);
920 if(!cs_malloc(&entry, sizeof(struct s_rlimit)))
922 fclose(fp);
923 return new_rlimit;
926 count++;
927 if (ratelimittime < 60) ratelimittime *=1000;
928 if (srvidholdtime < 60) srvidholdtime *=1000;
929 entry->rl.caid = caid;
930 entry->rl.provid = provid;
931 entry->rl.srvid = srvid;
932 entry->rl.chid = chid;
933 entry->rl.ratelimitecm = ratelimitecm;
934 entry->rl.ratelimittime = ratelimittime;
935 entry->rl.srvidholdtime = srvidholdtime;
937 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,
938 entry->rl.ratelimitecm, entry->rl.ratelimittime, entry->rl.srvidholdtime);
940 if(!new_rlimit)
942 new_rlimit = entry;
943 last = new_rlimit;
945 else
947 last->next = entry;
948 last = entry;
952 if(count)
953 { cs_log("%d entries read from %s", count, cs_ratelimit); }
955 fclose(fp);
957 return new_rlimit;
960 void ratelimit_read(void)
963 struct s_rlimit *entry, *old_list;
965 old_list = cfg.ratelimit_list;
966 cfg.ratelimit_list = ratelimit_read_int();
968 while(old_list)
970 entry = old_list->next;
971 NULLFREE(old_list);
972 old_list = entry;
976 struct ecmrl get_ratelimit(ECM_REQUEST *er)
979 struct ecmrl tmp;
980 memset(&tmp, 0, sizeof(tmp));
981 if(!cfg.ratelimit_list) { return tmp; }
982 struct s_rlimit *entry = cfg.ratelimit_list;
983 while(entry)
985 if(entry->rl.caid == er->caid && entry->rl.provid == er->prid && entry->rl.srvid == er->srvid && (!entry->rl.chid || entry->rl.chid == er->chid))
987 break;
989 entry = entry->next;
992 if(entry) { tmp = entry->rl; }
994 return (tmp);
997 int32_t init_tierid(void)
999 FILE *fp = open_config_file(cs_trid);
1000 if(!fp)
1001 { return 0; }
1003 int32_t nr;
1004 char *payload, *saveptr1 = NULL, *token;
1005 if(!cs_malloc(&token, MAXLINESIZE))
1006 { return 0; }
1007 static struct s_tierid *tierid = NULL, *new_cfg_tierid = NULL;
1009 nr = 0;
1010 while(fgets(token, MAXLINESIZE, fp))
1013 int32_t l;
1014 void *ptr;
1015 char *tmp, *tieridasc;
1016 tmp = trim(token);
1018 if(tmp[0] == '#') { continue; }
1019 if((l = strlen(tmp)) < 6) { continue; }
1020 if(!(payload = strchr(token, '|'))) { continue; }
1021 if(!(tieridasc = strchr(token, ':'))) { continue; }
1022 *payload++ = '\0';
1024 if(!cs_malloc(&ptr, sizeof(struct s_tierid)))
1026 NULLFREE(token);
1027 fclose(fp);
1028 return (1);
1030 if(tierid)
1031 { tierid->next = ptr; }
1032 else
1033 { new_cfg_tierid = ptr; }
1035 tierid = ptr;
1037 int32_t i;
1038 char *ptr1 = strtok_r(payload, "|", &saveptr1);
1039 if(ptr1)
1040 { cs_strncpy(tierid->name, trim(ptr1), sizeof(tierid->name)); }
1042 *tieridasc++ = '\0';
1043 tierid->tierid = dyn_word_atob(tieridasc);
1044 //printf("tierid %s - %d\n",tieridasc,tierid->tierid );
1046 tierid->ncaid = 0;
1047 for(i = 0, ptr1 = strtok_r(token, ",", &saveptr1); (ptr1) && (i < 10) ; ptr1 = strtok_r(NULL, ",", &saveptr1), i++)
1049 tierid->caid[i] = dyn_word_atob(ptr1);
1050 tierid->ncaid = i + 1;
1051 // cs_log("ld caid: %04X tierid: %04X name: %s",tierid->caid[i],tierid->tierid,tierid->name);
1053 nr++;
1055 NULLFREE(token);
1056 fclose(fp);
1057 if(nr > 0)
1058 { cs_log("%d tier-id's loaded", nr); }
1059 cs_writelock(__func__, &config_lock);
1060 //reload function:
1061 tierid = cfg.tierid;
1062 cfg.tierid = new_cfg_tierid;
1063 struct s_tierid *ptr;
1064 while(tierid)
1066 ptr = tierid->next;
1067 NULLFREE(tierid);
1068 tierid = ptr;
1070 cs_writeunlock(__func__, &config_lock);
1072 return (0);
1075 int32_t match_whitelist(ECM_REQUEST *er, struct s_global_whitelist *entry)
1077 return ((!entry->caid || entry->caid == er->caid)
1078 && (!entry->provid || entry->provid == er->prid)
1079 && (!entry->srvid || entry->srvid == er->srvid)
1080 && (!entry->chid || entry->chid == er->chid)
1081 && (!entry->pid || entry->pid == er->pid)
1082 && (!entry->ecmlen || entry->ecmlen == er->ecmlen));
1085 int32_t chk_global_whitelist(ECM_REQUEST *er, uint32_t *line)
1087 *line = -1;
1088 if(!cfg.global_whitelist)
1089 { return 1; }
1091 struct s_global_whitelist *entry;
1093 //check mapping:
1094 if(cfg.global_whitelist_use_m)
1096 entry = cfg.global_whitelist;
1097 while(entry)
1099 if(entry->type == 'm')
1101 if(match_whitelist(er, entry))
1103 er->caid = entry->mapcaid;
1104 er->prid = entry->mapprovid;
1105 cs_log_dbg(D_TRACE, "whitelist: mapped %04X@%06X to %04X@%06X", er->caid, er->prid, entry->mapcaid, entry->mapprovid);
1106 break;
1109 entry = entry->next;
1113 if(cfg.global_whitelist_use_l) //Check caid/prov/srvid etc matching, except ecm-len:
1115 entry = cfg.global_whitelist;
1116 int8_t caidprov_matches = 0;
1117 while(entry)
1119 if(entry->type == 'l')
1121 if(match_whitelist(er, entry))
1123 *line = entry->line;
1124 return 1;
1126 if((!entry->caid || entry->caid == er->caid)
1127 && (!entry->provid || entry->provid == er->prid)
1128 && (!entry->srvid || entry->srvid == er->srvid)
1129 && (!entry->chid || entry->chid == er->chid)
1130 && (!entry->pid || entry->pid == er->pid))
1132 caidprov_matches = 1;
1133 *line = entry->line;
1136 entry = entry->next;
1138 if(caidprov_matches) //...but not ecm-len!
1139 { return 0; }
1142 entry = cfg.global_whitelist;
1143 while(entry)
1145 if(match_whitelist(er, entry))
1147 *line = entry->line;
1148 if(entry->type == 'w')
1149 { return 1; }
1150 else if(entry->type == 'i')
1151 { return 0; }
1153 entry = entry->next;
1155 return 0;
1158 //Format:
1159 //Whitelist-Entry:
1160 //w:caid:prov:srvid:pid:chid:ecmlen
1161 //Ignore-Entry:
1162 //i:caid:prov:srvid:pid:chid:ecmlen
1163 //ECM len check - Entry:
1164 //l:caid:prov:srvid:pid:chid:ecmlen
1166 //Mapping:
1167 //m:caid:prov:srvid:pid:chid:ecmlen caidto:provto
1169 static struct s_global_whitelist *global_whitelist_read_int(void)
1171 FILE *fp = open_config_file(cs_whitelist);
1172 if(!fp)
1173 { return NULL; }
1175 char token[1024], str1[1024];
1176 unsigned char type;
1177 int32_t i, ret, count = 0;
1178 struct s_global_whitelist *new_whitelist = NULL, *entry, *last = NULL;
1179 uint32_t line = 0;
1181 cfg.global_whitelist_use_l = 0;
1182 cfg.global_whitelist_use_m = 0;
1184 while(fgets(token, sizeof(token), fp))
1186 line++;
1187 if(strlen(token) <= 1) { continue; }
1188 if(token[0] == '#' || token[0] == '/') { continue; }
1189 if(strlen(token) > 1024) { continue; }
1191 for(i = 0; i < (int)strlen(token); i++)
1193 if((token[i] == ':' || token[i] == ' ') && token[i + 1] == ':')
1195 memmove(token + i + 2, token + i + 1, strlen(token) - i + 1);
1196 token[i + 1] = '0';
1198 if(token[i] == '#' || token[i] == '/')
1200 token[i] = '\0';
1201 break;
1205 type = 'w';
1206 uint32_t caid = 0, provid = 0, srvid = 0, pid = 0, chid = 0, ecmlen = 0, mapcaid = 0, mapprovid = 0;
1207 memset(str1, 0, sizeof(str1));
1209 ret = sscanf(token, "%c:%4x:%6x:%4x:%4x:%4x:%1023s", &type, &caid, &provid, &srvid, &pid, &chid, str1);
1211 type = tolower(type);
1213 //w=whitelist
1214 //i=ignore
1215 //l=len-check
1216 //m=map caid/prov
1217 if(ret < 1 || (type != 'w' && type != 'i' && type != 'l' && type != 'm'))
1218 { continue; }
1220 if(type == 'm')
1222 char *p = strstr(token + 4, " ");
1223 if(!p || sscanf(p + 1, "%4x:%6x", &mapcaid, &mapprovid) < 2)
1225 cs_log_dbg(D_TRACE, "whitelist: wrong mapping: %s", token);
1226 continue;
1228 str1[0] = 0;
1229 cfg.global_whitelist_use_m = 1;
1231 strncat(str1, ",", sizeof(str1) - strlen(str1) - 1);
1232 char *p = str1, *p2 = str1;
1233 while(*p)
1235 if(*p == ',')
1237 *p = 0;
1238 ecmlen = 0;
1239 sscanf(p2, "%4x", &ecmlen);
1241 if(!cs_malloc(&entry, sizeof(struct s_global_whitelist)))
1243 fclose(fp);
1244 return new_whitelist;
1247 count++;
1248 entry->line = line;
1249 entry->type = type;
1250 entry->caid = caid;
1251 entry->provid = provid;
1252 entry->srvid = srvid;
1253 entry->pid = pid;
1254 entry->chid = chid;
1255 entry->ecmlen = ecmlen;
1256 entry->mapcaid = mapcaid;
1257 entry->mapprovid = mapprovid;
1258 if(entry->type == 'l')
1259 { cfg.global_whitelist_use_l = 1; }
1261 if(type == 'm')
1262 cs_log_dbg(D_TRACE,
1263 "whitelist: %c: %04X@%06X:%04X:%04X:%04X:%02X map to %04X@%06X", entry->type, entry->caid, entry->provid, entry->srvid, entry->pid, entry->chid, entry->ecmlen, entry->mapcaid, entry->mapprovid);
1264 else
1265 cs_log_dbg(D_TRACE,
1266 "whitelist: %c: %04X@%06X:%04X:%04X:%04X:%02X", entry->type, entry->caid, entry->provid, entry->srvid, entry->pid, entry->chid, entry->ecmlen);
1268 if(!new_whitelist)
1270 new_whitelist = entry;
1271 last = new_whitelist;
1273 else
1275 last->next = entry;
1276 last = entry;
1279 p2 = p + 1;
1281 p++;
1285 if(count)
1286 { cs_log("%d entries read from %s", count, cs_whitelist); }
1288 fclose(fp);
1290 return new_whitelist;
1293 void global_whitelist_read(void)
1296 struct s_global_whitelist *entry, *old_list;
1298 old_list = cfg.global_whitelist;
1299 cfg.global_whitelist = global_whitelist_read_int();
1301 while(old_list)
1303 entry = old_list->next;
1304 NULLFREE(old_list);
1305 old_list = entry;
1309 void init_len4caid(void)
1311 FILE *fp = open_config_file(cs_l4ca);
1312 if(!fp)
1313 { return; }
1315 int32_t nr;
1316 char *value, *token;
1318 if(!cs_malloc(&token, MAXLINESIZE))
1319 { return; }
1321 memset(len4caid, 0, sizeof(uint16_t) << 8);
1322 for(nr = 0; fgets(token, MAXLINESIZE, fp);)
1324 int32_t i, c;
1325 char *ptr;
1326 if(!(value = strchr(token, ':')))
1327 { continue; }
1328 *value++ = '\0';
1329 if((ptr = strchr(value, '#')))
1330 { * ptr = '\0'; }
1331 if(strlen(trim(token)) != 2)
1332 { continue; }
1333 if(strlen(trim(value)) != 4)
1334 { continue; }
1335 if((i = byte_atob(token)) < 0)
1336 { continue; }
1337 if((c = word_atob(value)) < 0)
1338 { continue; }
1339 len4caid[i] = c;
1340 nr++;
1342 NULLFREE(token);
1343 fclose(fp);
1344 if(nr)
1345 { cs_log("%d lengths for caid guessing loaded", nr); }
1346 return;
1349 #ifdef MODULE_SERIAL
1350 static struct s_twin *twin_read_int(void)
1352 FILE *fp = open_config_file(cs_twin);
1353 if(!fp)
1354 { return NULL; }
1355 char token[1024], str1[1024];
1356 int32_t i, ret, count = 0;
1357 struct s_twin *new_twin = NULL, *entry, *last = NULL;
1358 uint32_t line = 0;
1360 while(fgets(token, sizeof(token), fp))
1362 line++;
1363 if(strlen(token) <= 1) { continue; }
1364 if(token[0] == '#' || token[0] == '/') { continue; }
1365 if(strlen(token) > 1024) { continue; }
1367 for(i = 0; i < (int)strlen(token); i++)
1369 if((token[i] == ':' || token[i] == ' ') && token[i + 1] == ':')
1371 memmove(token + i + 2, token + i + 1, strlen(token) - i + 1);
1372 token[i + 1] = '0';
1374 if(token[i] == '#' || token[i] == '/' || token[i] == '"')
1376 token[i] = '\0';
1377 break;
1381 uint32_t caid = 0, provid = 0, srvid = 0, deg = 0, freq = 0;
1382 // char hdeg[4], hfreq[4], hsrvid[4];
1383 memset(str1, 0, sizeof(str1));
1385 ret = sscanf(token, "%4x:%6x:%d:%d:%d", &caid, &provid, &deg, &freq, &srvid);
1386 if(ret < 1) { continue; }
1387 // snprintf(hdeg, 4, "%x", deg);
1388 // sscanf(hdeg, "%4x", &deg);
1389 // snprintf(hfreq, 4, "%x", freq);
1390 // sscanf(hfreq, "%4x", &freq);
1391 // snprintf(hsrvid, 4, "%x", srvid);
1392 // sscanf(hsrvid, "%4x", &srvid);
1393 strncat(str1, ",", sizeof(str1) - strlen(str1) - 1);
1394 if(!cs_malloc(&entry, sizeof(struct s_twin)))
1396 fclose(fp);
1397 return new_twin;
1400 count++;
1401 entry->tw.caid = caid;
1402 entry->tw.provid = provid;
1403 entry->tw.srvid = srvid;
1404 entry->tw.deg = deg;
1405 entry->tw.freq = freq;
1407 cs_debug_mask(D_TRACE, "channel: %04X:%06X:%d:%d:%d", entry->tw.caid, entry->tw.provid, entry->tw.deg,
1408 entry->tw.freq, entry->tw.srvid);
1410 if(!new_twin)
1412 new_twin = entry;
1413 last = new_twin;
1415 else
1417 last->next = entry;
1418 last = entry;
1422 if(count)
1423 { cs_log("%d entries read from %s", count, cs_twin); }
1425 fclose(fp);
1427 return new_twin;
1430 void twin_read(void)
1433 struct s_twin *entry, *old_list;
1435 old_list = cfg.twin_list;
1436 cfg.twin_list = twin_read_int();
1438 while(old_list)
1440 entry = old_list->next;
1441 free(old_list);
1442 old_list = entry;
1446 struct ecmtw get_twin(ECM_REQUEST *er)
1448 struct ecmtw tmp;
1449 memset(&tmp, 0, sizeof(tmp));
1450 if(!cfg.twin_list)
1452 cs_log("twin_list not found!");
1453 return tmp;
1455 struct s_twin *entry = cfg.twin_list;
1456 while(entry)
1458 if(entry->tw.caid == er->caid && entry->tw.provid == er->prid && entry->tw.srvid == er->srvid)
1460 break;
1462 entry = entry->next;
1465 if(entry) { tmp = entry->tw; }
1467 return (tmp);
1469 #endif