source: trunk/oscam-config.c@ 11719

Last change on this file since 11719 was 11719, checked in by bust3d, 6 months ago

Fixing Mapping LOG thanks to @Qu4k3
Nagra fix thanks to @w33dburner

  • Property svn:eol-style set to LF
File size: 33.6 KB
Line 
1#define MODULE_LOG_PREFIX "config"
2
3//FIXME Not checked on threadsafety yet; after checking please remove this line
4
5#include "globals.h"
6
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"
15
16extern uint16_t len4caid[256];
17
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"
27
28uint32_t cfg_sidtab_generation = 1;
29uint32_t caid;
30
31extern char cs_confdir[];
32
33char *get_config_filename(char *dest, size_t destlen, const char *filename)
34{
35 // cs_confdir is always terminated with /
36 snprintf(dest, destlen, "%s%s", cs_confdir, filename);
37 return dest;
38}
39
40int32_t write_services(void)
41{
42 int32_t i;
43 struct s_sidtab *sidtab = cfg.sidtab;
44 char *ptr;
45 FILE *f = create_config_file(cs_sidt);
46 if(!f)
47 { return 1; }
48
49 while(sidtab != NULL)
50 {
51 ptr = sidtab->label;
52 while(*ptr)
53 {
54 if(*ptr == ' ') { *ptr = '_'; }
55 ptr++;
56 }
57 fprintf(f, "[%s]\n", sidtab->label);
58#ifdef CS_CACHEEX_AIO
59 fprintf_conf(f, "disablecrccws_only_for_exception", "%u", sidtab->disablecrccws_only_for_exception); // it should not have \n at the end
60 fputc((int)'\n', f);
61 fprintf_conf(f, "no_wait_time", "%u", sidtab->no_wait_time); // it should not have \n at the end
62 fputc((int)'\n', f);
63 fprintf_conf(f, "lg_only_exception", "%u", sidtab->lg_only_exception); // it should not have \n at the end
64 fputc((int)'\n', f);
65#endif
66 fprintf_conf(f, "caid", "%s", ""); // it should not have \n at the end
67 for(i = 0; i < sidtab->num_caid; i++)
68 {
69 if(i == 0) { fprintf(f, "%04X", sidtab->caid[i]); }
70 else { fprintf(f, ",%04X", sidtab->caid[i]); }
71 }
72 fputc((int)'\n', f);
73 fprintf_conf(f, "provid", "%s", ""); // it should not have \n at the end
74 for(i = 0; i < sidtab->num_provid; i++)
75 {
76 if(i == 0) { fprintf(f, "%06X", sidtab->provid[i]); }
77 else { fprintf(f, ",%06X", sidtab->provid[i]); }
78 }
79 fputc((int)'\n', f);
80 fprintf_conf(f, "srvid", "%s", ""); // it should not have \n at the end
81 for(i = 0; i < sidtab->num_srvid; i++)
82 {
83 if(i == 0) { fprintf(f, "%04X", sidtab->srvid[i]); }
84 else { fprintf(f, ",%04X", sidtab->srvid[i]); }
85 }
86 fprintf(f, "\n\n");
87 sidtab = sidtab->next;
88 }
89
90 return flush_config_file(f, cs_sidt);
91}
92
93void free_sidtab(struct s_sidtab *ptr)
94{
95 if(!ptr) { return; }
96 add_garbage(ptr->caid); //no need to check on NULL first, freeing NULL doesnt do anything
97 add_garbage(ptr->provid);
98 add_garbage(ptr->srvid);
99 add_garbage(ptr);
100}
101
102static void chk_entry4sidtab(char *value, struct s_sidtab *sidtab, int32_t what)
103{
104 int32_t i, b;
105 char *ptr, *saveptr1 = NULL;
106 uint16_t *slist = (uint16_t *) 0;
107 uint32_t *llist = (uint32_t *) 0;
108#ifdef CS_CACHEEX_AIO
109 uint8_t disablecrccws_only_for_exception = 0;
110 uint8_t no_wait_time = 0;
111 uint8_t lg_only_exception = 0;
112#endif
113 char buf[cs_strlen(value) + 1];
114 cs_strncpy(buf, value, sizeof(buf));
115
116#ifdef CS_CACHEEX_AIO
117 if(what == 5) // lg_only_exception
118 {
119 sidtab->lg_only_exception = a2i(buf, sizeof(lg_only_exception));
120 return;
121 }
122
123 if(what == 4) // no_wait_time
124 {
125 sidtab->no_wait_time = a2i(buf, sizeof(no_wait_time));
126 return;
127 }
128
129 if(what == 3) // disablecrccws_only_for_exception
130 {
131 sidtab->disablecrccws_only_for_exception = a2i(buf, sizeof(disablecrccws_only_for_exception));
132 return;
133 }
134#endif
135
136 b = (what == 1) ? sizeof(uint32_t) : sizeof(uint16_t);
137
138 for(i = 0, ptr = strtok_r(value, ",", &saveptr1); ptr; ptr = strtok_r(NULL, ",", &saveptr1))
139 {
140 caid = a2i(ptr, b);
141 if(!errno) { i++; }
142 }
143 //if (!i) return(0);
144 if(b == sizeof(uint16_t))
145 {
146 if(!cs_malloc(&slist, i * sizeof(uint16_t))) { return; }
147 }
148 else
149 {
150 if(!cs_malloc(&llist, i * sizeof(uint32_t))) { return; }
151 }
152 cs_strncpy(value, buf, sizeof(buf));
153 for(i = 0, ptr = strtok_r(value, ",", &saveptr1); ptr; ptr = strtok_r(NULL, ",", &saveptr1))
154 {
155 caid = a2i(ptr, b);
156 if(errno) { continue; }
157 if(b == sizeof(uint16_t))
158 { slist[i++] = (uint16_t) caid; }
159 else
160 { llist[i++] = caid; }
161 }
162 switch(what)
163 {
164 case 0:
165 add_garbage(sidtab->caid);
166 sidtab->caid = slist;
167 sidtab->num_caid = i;
168 break;
169 case 1:
170 add_garbage(sidtab->provid);
171 sidtab->provid = llist;
172 sidtab->num_provid = i;
173 break;
174 case 2:
175 add_garbage(sidtab->srvid);
176 sidtab->srvid = slist;
177 sidtab->num_srvid = i;
178 break;
179 }
180}
181
182void chk_sidtab(char *token, char *value, struct s_sidtab *sidtab)
183{
184 if(!strcmp(token, "caid"))
185 {
186 chk_entry4sidtab(value, sidtab, 0);
187 return;
188 }
189 if(!strcmp(token, "provid"))
190 {
191 chk_entry4sidtab(value, sidtab, 1);
192 return;
193 }
194 if(!strcmp(token, "ident"))
195 {
196 chk_entry4sidtab(value, sidtab, 1);
197 return;
198 }
199 if(!strcmp(token, "srvid"))
200 {
201 chk_entry4sidtab(value, sidtab, 2);
202 return;
203 }
204#ifdef CS_CACHEEX_AIO
205 if(!strcmp(token, "disablecrccws_only_for_exception"))
206 {
207 chk_entry4sidtab(value, sidtab, 3);
208 return;
209 }
210 if(!strcmp(token, "no_wait_time"))
211 {
212 chk_entry4sidtab(value, sidtab, 4);
213 return;
214 }
215 if(!strcmp(token, "lg_only_exception"))
216 {
217 chk_entry4sidtab(value, sidtab, 5);
218 return;
219 }
220#endif
221 if(token[0] != '#')
222 { fprintf(stderr, "Warning: keyword '%s' in sidtab section not recognized\n", token); }
223}
224
225void init_free_sidtab(void)
226{
227 struct s_sidtab *nxt, *ptr = cfg.sidtab;
228 while(ptr)
229 {
230 nxt = ptr->next;
231 free_sidtab(ptr);
232 ptr = nxt;
233 }
234 cfg.sidtab = NULL;
235 ++cfg_sidtab_generation;
236}
237
238//#define DEBUG_SIDTAB 1
239#ifdef DEBUG_SIDTAB
240static void show_sidtab(struct s_sidtab *sidtab)
241{
242 for(; sidtab; sidtab = sidtab->next)
243 {
244 int32_t i;
245 char buf[1024];
246 char *saveptr = buf;
247 cs_log("label=%s", sidtab->label);
248#ifdef CS_CACHEEX_AIO
249 cs_log("disablecrccws_only_for_exception=%u", sidtab->disablecrccws_only_for_exception);
250 cs_log("no_wait_time=%u", sidtab->no_wait_time);
251 cs_log("lg_only_exception=%u", sidtab->lg_only_exception);
252#endif
253 snprintf(buf, sizeof(buf), "caid(%d)=", sidtab->num_caid);
254 for(i = 0; i < sidtab->num_caid; i++)
255 { snprintf(buf + cs_strlen(buf), 1024 - (buf - saveptr), "%04X ", sidtab->caid[i]); }
256 cs_log("%s", buf);
257 snprintf(buf, sizeof(buf), "provider(%d)=", sidtab->num_provid);
258 for(i = 0; i < sidtab->num_provid; i++)
259 { snprintf(buf + cs_strlen(buf), 1024 - (buf - saveptr), "%08X ", sidtab->provid[i]); }
260 cs_log("%s", buf);
261 snprintf(buf, sizeof(buf), "services(%d)=", sidtab->num_srvid);
262 for(i = 0; i < sidtab->num_srvid; i++)
263 { snprintf(buf + cs_strlen(buf), 1024 - (buf - saveptr), "%04X ", sidtab->srvid[i]); }
264 cs_log("%s", buf);
265 }
266}
267#else
268static void show_sidtab(struct s_sidtab *UNUSED(sidtab)) { }
269#endif
270
271int32_t init_sidtab(void)
272{
273 FILE *fp = open_config_file(cs_sidt);
274 if(!fp)
275 { return 1; }
276
277 int32_t nr, nro, nrr;
278 char *value, *token;
279 if(!cs_malloc(&token, MAXLINESIZE))
280 { return 1; }
281 struct s_sidtab *ptr;
282 struct s_sidtab *sidtab = (struct s_sidtab *)0;
283
284 for(nro = 0, ptr = cfg.sidtab; ptr; nro++)
285 {
286 struct s_sidtab *ptr_next;
287 ptr_next = ptr->next;
288 free_sidtab(ptr);
289 ptr = ptr_next;
290 }
291 nr = 0;
292 nrr = 0;
293 while(fgets(token, MAXLINESIZE, fp))
294 {
295 int32_t l;
296 if((l = cs_strlen(trim(token))) < 3) { continue; }
297 if((token[0] == '[') && (token[l - 1] == ']'))
298 {
299 token[l - 1] = 0;
300 if(nr > MAX_SIDBITS)
301 {
302 fprintf(stderr, "Warning: Service No.%d - '%s' ignored. Max allowed Services %d\n", nr, strtolower(token + 1), MAX_SIDBITS);
303 nr++;
304 nrr++;
305 }
306 else
307 {
308 if(!cs_malloc(&ptr, sizeof(struct s_sidtab)))
309 {
310 NULLFREE(token);
311 return (1);
312 }
313 if(sidtab)
314 { sidtab->next = ptr; }
315 else
316 { cfg.sidtab = ptr; }
317 sidtab = ptr;
318 nr++;
319 cs_strncpy(sidtab->label, strtolower(token + 1), sizeof(sidtab->label));
320 continue;
321 }
322 }
323 if(!sidtab) { continue; }
324 if(!(value = strchr(token, '='))) { continue; }
325 *value++ = '\0';
326 chk_sidtab(trim(strtolower(token)), trim(strtolower(value)), sidtab);
327 }
328 NULLFREE(token);
329 fclose(fp);
330
331 show_sidtab(cfg.sidtab);
332 ++cfg_sidtab_generation;
333 cs_log("services reloaded: %d services freed, %d services loaded, rejected %d", nro, nr, nrr);
334 return (0);
335}
336
337int32_t init_provid(void)
338{
339 FILE *fp = open_config_file(cs_provid);
340 if(!fp)
341 { return 0; }
342
343 int32_t nr;
344 char *payload, *saveptr1 = NULL, *token;
345 if(!cs_malloc(&token, MAXLINESIZE))
346 { return 0; }
347 struct s_provid *provid_ptr = NULL;
348 struct s_provid *new_cfg_provid = NULL, *last_provid;
349
350 nr = 0;
351 while(fgets(token, MAXLINESIZE, fp))
352 {
353 int32_t i;
354 struct s_provid *new_provid = NULL;
355 char *tmp, *ptr1;
356
357 tmp = trim(token);
358
359 if(tmp[0] == '#') { continue; }
360 if(cs_strlen(tmp) < 11) { continue; }
361 if(!(payload = strchr(token, '|'))) { continue; }
362
363 *payload++ = '\0';
364
365 if(!cs_malloc(&new_provid, sizeof(struct s_provid)))
366 {
367 NULLFREE(token);
368 fclose(fp);
369 return (1);
370 }
371
372 new_provid->nprovid = 0;
373 for(i = 0, ptr1 = strtok_r(token, ":@", &saveptr1); ptr1; ptr1 = strtok_r(NULL, ":@", &saveptr1), i++)
374 {
375 if(i==0)
376 {
377 new_provid->caid = a2i(ptr1, 3);
378 continue;
379 }
380
381 new_provid->nprovid++;
382 }
383
384 if(!cs_malloc(&new_provid->provid, sizeof(uint32_t) * new_provid->nprovid))
385 {
386 NULLFREE(new_provid);
387 NULLFREE(token);
388 fclose(fp);
389 return (1);
390 }
391
392 ptr1 = token + cs_strlen(token) + 1;
393 for(i = 0; i < new_provid->nprovid ; i++)
394 {
395 new_provid->provid[i] = a2i(ptr1, 3);
396
397 ptr1 = ptr1 + cs_strlen(ptr1) + 1;
398 }
399
400 for(i = 0, ptr1 = strtok_r(payload, "|", &saveptr1); ptr1; ptr1 = strtok_r(NULL, "|", &saveptr1), i++)
401 {
402 switch(i)
403 {
404 case 0:
405 cs_strncpy(new_provid->prov, trim(ptr1), sizeof(new_provid->prov));
406 break;
407 case 1:
408 cs_strncpy(new_provid->sat, trim(ptr1), sizeof(new_provid->sat));
409 break;
410 case 2:
411 cs_strncpy(new_provid->lang, trim(ptr1), sizeof(new_provid->lang));
412 break;
413 }
414 }
415
416 if(cs_strlen(new_provid->prov) == 0)
417 {
418 NULLFREE(new_provid->provid);
419 NULLFREE(new_provid);
420 continue;
421 }
422
423 nr++;
424
425 if(provid_ptr)
426 {
427 provid_ptr->next = new_provid;
428 }
429 else
430 {
431 new_cfg_provid = new_provid;
432 }
433 provid_ptr = new_provid;
434 }
435
436 NULLFREE(token);
437 fclose(fp);
438
439 if(nr > 0)
440 { cs_log("%d provid's loaded", nr); }
441
442 if(new_cfg_provid == NULL)
443 {
444 if(!cs_malloc(&new_cfg_provid, sizeof(struct s_provid)))
445 {
446 return (1);
447 }
448 }
449
450 cs_writelock(__func__, &config_lock);
451
452 // this allows reloading of provids, so cleanup of old data is needed:
453 last_provid = cfg.provid; // old data
454 cfg.provid = new_cfg_provid; // assign after loading, so everything is in memory
455
456 cs_writeunlock(__func__, &config_lock);
457
458 struct s_client *cl;
459 for(cl = first_client->next; cl ; cl = cl->next)
460 { cl->last_providptr = NULL; }
461
462 struct s_provid *ptr, *nptr;
463
464 if(last_provid)
465 {
466 ptr = last_provid;
467 while(ptr) // cleanup old data:
468 {
469 add_garbage(ptr->provid);
470 nptr = ptr->next;
471 add_garbage(ptr);
472 ptr = nptr;
473 }
474 }
475
476 return (0);
477}
478
479int32_t init_srvid(void)
480{
481 int8_t new_syntax = 1;
482 FILE *fp = open_config_file("oscam.srvid2");
483 if(!fp)
484 {
485 fp = open_config_file(cs_srid);
486 if(fp)
487 {
488 new_syntax = 0;
489 }
490 }
491
492 if(!fp)
493 {
494 fp = create_config_file("oscam.srvid2");
495 if(fp)
496 {
497 flush_config_file(fp, "oscam.srvid2");
498 }
499
500 return 0;
501 }
502
503 int32_t nr = 0, i, j;
504 char *payload, *saveptr1 = NULL, *saveptr2 = NULL, *token;
505 const char *tmp;
506 if(!cs_malloc(&token, MAXLINESIZE))
507 { return 0; }
508 struct s_srvid *srvid = NULL, *new_cfg_srvid[16], *last_srvid[16];
509 // A cache for strings within srvids. A checksum is calculated which is the start point in the array (some kind of primitive hash algo).
510 // From this point, a sequential search is done. This greatly reduces the amount of string comparisons.
511 const char **stringcache[1024];
512 int32_t allocated[1024] = { 0 };
513 int32_t used[1024] = { 0 };
514 struct timeb ts, te;
515 cs_ftime(&ts);
516
517 memset(last_srvid, 0, sizeof(last_srvid));
518 memset(new_cfg_srvid, 0, sizeof(new_cfg_srvid));
519
520 while(fgets(token, MAXLINESIZE, fp))
521 {
522 int32_t len = 0, len2, srvidtmp;
523 uint32_t k;
524 uint32_t pos;
525 char *srvidasc, *prov;
526 tmp = trim(token);
527
528 if(tmp[0] == '#') { continue; }
529 if(cs_strlen(tmp) < 6) { continue; }
530 if(!(srvidasc = strchr(token, ':'))) { continue; }
531 if(!(payload = strchr(token, '|'))) { continue; }
532 *payload++ = '\0';
533
534 if(!cs_malloc(&srvid, sizeof(struct s_srvid)))
535 {
536 NULLFREE(token);
537 fclose(fp);
538 return (1);
539 }
540
541 char tmptxt[128];
542
543 int32_t offset[4] = { -1, -1, -1, -1 };
544 char *ptr1 = NULL, *ptr2 = NULL;
545 const char *searchptr[4] = { NULL, NULL, NULL, NULL };
546 const char **ptrs[4] = { &srvid->prov, &srvid->name, &srvid->type, &srvid->desc };
547 uint32_t max_payload_length = MAXLINESIZE - (payload - token);
548
549 if(new_syntax)
550 {
551 ptrs[0] = &srvid->name;
552 ptrs[1] = &srvid->type;
553 ptrs[2] = &srvid->desc;
554 ptrs[3] = &srvid->prov;
555 }
556
557 // allow empty strings as "||"
558 if(payload[0] == '|' && (cs_strlen(payload) + 2 < max_payload_length))
559 {
560 memmove(payload+1, payload, cs_strlen(payload)+1);
561 payload[0] = ' ';
562 }
563
564 for(k = 1; ((k < max_payload_length) && (payload[k] != '\0')); k++)
565 {
566 if(payload[k - 1] == '|' && payload[k] == '|')
567 {
568 if(cs_strlen(payload + k) + 2 < max_payload_length-k)
569 {
570 memmove(payload + k + 1, payload + k, cs_strlen(payload + k) + 1);
571 payload[k] = ' ';
572 }
573 else
574 {
575 break;
576 }
577 }
578 }
579
580 for(i = 0, ptr1 = strtok_r(payload, "|", &saveptr1); ptr1 && (i < 4) ; ptr1 = strtok_r(NULL, "|", &saveptr1), ++i)
581 {
582 // check if string is in cache
583 len2 = cs_strlen(ptr1);
584 pos = 0;
585 for(j = 0; j < len2; ++j) { pos += (uint8_t)ptr1[j]; }
586 pos = pos % 1024;
587 for(j = 0; j < used[pos]; ++j)
588 {
589 if(!strcmp(stringcache[pos][j], ptr1))
590 {
591 searchptr[i] = stringcache[pos][j];
592 break;
593 }
594 }
595 if(searchptr[i]) { continue; }
596
597 offset[i] = len;
598 cs_strncpy(tmptxt + len, trim(ptr1), sizeof(tmptxt) - len);
599 len += cs_strlen(ptr1) + 1;
600 }
601
602 char *tmpptr = NULL;
603 if(len > 0 && !cs_malloc(&tmpptr, len))
604 { continue; }
605
606 srvid->data = tmpptr;
607 if(len > 0) { memcpy(tmpptr, tmptxt, len); }
608
609 for(i = 0; i < 4; i++)
610 {
611 if(searchptr[i])
612 {
613 *ptrs[i] = searchptr[i];
614 continue;
615 }
616 if(offset[i] > -1)
617 {
618 *ptrs[i] = tmpptr + offset[i];
619 // store string in stringcache
620 if (*ptrs[i])
621 {
622 tmp = *ptrs[i];
623 len2 = cs_strlen(tmp);
624 }
625 else
626 {
627 cs_log("FIXME! len2!");
628 len2 = 0;
629 }
630
631 pos = 0;
632 for(j = 0; j < len2; ++j) { pos += (uint8_t)tmp[j]; }
633 if (pos > 0)
634 {
635 pos = pos % 1024;
636 }
637 if(used[pos] >= allocated[pos])
638 {
639 if(allocated[pos] == 0)
640 {
641 if(!cs_malloc(&stringcache[pos], 16 * sizeof(char *)))
642 { break; }
643 }
644 else
645 {
646 if(!cs_realloc(&stringcache[pos], (allocated[pos] + 16) * sizeof(char *)))
647 { break; }
648 }
649 allocated[pos] += 16;
650 }
651 if (tmp[0])
652 {
653 stringcache[pos][used[pos]] = tmp;
654 used[pos] += 1;
655 }
656 }
657 }
658
659 *srvidasc++ = '\0';
660 if(new_syntax)
661 { srvidtmp = dyn_word_atob(token) & 0xFFFF; }
662 else
663 { srvidtmp = dyn_word_atob(srvidasc) & 0xFFFF; }
664
665 if(srvidtmp < 0)
666 {
667 NULLFREE(tmpptr);
668 NULLFREE(srvid);
669 continue;
670 }
671 else
672 {
673 srvid->srvid = srvidtmp;
674 }
675
676 srvid->ncaid = 0;
677 for(i = 0, ptr1 = strtok_r(new_syntax ? srvidasc : token, ",", &saveptr1); (ptr1); ptr1 = strtok_r(NULL, ",", &saveptr1), i++)
678 {
679 srvid->ncaid++;
680 }
681
682 if(!cs_malloc(&srvid->caid, sizeof(struct s_srvid_caid) * srvid->ncaid))
683 {
684 NULLFREE(tmpptr);
685 NULLFREE(srvid);
686 return 0;
687 }
688
689 ptr1 = new_syntax ? srvidasc : token;
690 for(i = 0; i < srvid->ncaid; i++)
691 {
692 prov = strchr(ptr1,'@');
693
694 srvid->caid[i].nprovid = 0;
695
696 if(prov)
697 {
698 if(prov[1] != '\0')
699 {
700 for(j = 0, ptr2 = strtok_r(prov+1, "@", &saveptr2); (ptr2); ptr2 = strtok_r(NULL, "@", &saveptr2), j++)
701 {
702 srvid->caid[i].nprovid++;
703 }
704
705 if(!cs_malloc(&srvid->caid[i].provid, sizeof(uint32_t) * srvid->caid[i].nprovid))
706 {
707 for(j = 0; j < i; j++)
708 { NULLFREE(srvid->caid[j].provid); }
709 NULLFREE(srvid->caid);
710 NULLFREE(tmpptr);
711 NULLFREE(srvid);
712 return 0;
713 }
714
715 ptr2 = prov + 1;
716 for(j = 0; j < srvid->caid[i].nprovid; j++)
717 {
718 srvid->caid[i].provid[j] = dyn_word_atob(ptr2) & 0xFFFFFF;
719 ptr2 = ptr2 + cs_strlen(ptr2) + 1;
720 }
721 }
722 else
723 {
724 ptr2 = prov + 2;
725 }
726
727 prov[0] = '\0';
728 }
729
730 srvid->caid[i].caid = dyn_word_atob(ptr1) & 0xFFFF;
731 if(prov)
732 { ptr1 = ptr2; }
733 else
734 { ptr1 = ptr1 + cs_strlen(ptr1) + 1; }
735 }
736
737 nr++;
738
739 if(new_cfg_srvid[srvid->srvid >> 12])
740 { last_srvid[srvid->srvid >> 12]->next = srvid; }
741 else
742 { new_cfg_srvid[srvid->srvid >> 12] = srvid; }
743
744 last_srvid[srvid->srvid >> 12] = srvid;
745 }
746 for(i = 0; i < 1024; ++i)
747 {
748 if(allocated[i] > 0) { NULLFREE(stringcache[i]); }
749 }
750 NULLFREE(token);
751
752 cs_ftime(&te);
753 int64_t load_time = comp_timeb(&te, &ts);
754
755 fclose(fp);
756 if(nr > 0)
757 {
758 cs_log("%d service-id's loaded in %"PRId64" ms", nr, load_time);
759 if(nr > 2000)
760 {
761 cs_log("WARNING: You risk high CPU load and high ECM times with more than 2000 service-id's!");
762 cs_log("HINT: --> use optimized lists from https://wiki.streamboard.tv/wiki/Srvid");
763 }
764 }
765
766 cs_writelock(__func__, &config_lock);
767 // this allows reloading of srvids, so cleanup of old data is needed:
768 memcpy(last_srvid, cfg.srvid, sizeof(last_srvid)); //old data
769 memcpy(cfg.srvid, new_cfg_srvid, sizeof(last_srvid)); //assign after loading, so everything is in memory
770
771 cs_writeunlock(__func__, &config_lock);
772
773 struct s_client *cl;
774 for(cl = first_client->next; cl ; cl = cl->next)
775 { cl->last_srvidptr = NULL; }
776
777 struct s_srvid *ptr, *nptr;
778
779 for(i = 0; i < 16; i++)
780 {
781 ptr = last_srvid[i];
782 while(ptr) // cleanup old data:
783 {
784 for(j = 0; j < ptr->ncaid; j++)
785 { add_garbage(ptr->caid[j].provid); }
786 add_garbage(ptr->caid);
787 add_garbage(ptr->data);
788 nptr = ptr->next;
789 add_garbage(ptr);
790 ptr = nptr;
791 }
792 }
793
794 return (0);
795}
796
797int32_t init_fakecws(void)
798{
799 int32_t nr = 0, i, j, idx;
800 uint32_t alloccount[0x100], count[0x100], tmp, max_compares = 0, average_compares = 0;
801 char *token, cw_string[64];
802 uint8_t cw[16], wrong_checksum, c, have_fakecw = 0;
803 FILE *fp;
804
805 memset(alloccount, 0, sizeof(count));
806 memset(count, 0, sizeof(alloccount));
807
808 cs_writelock(__func__, &config_lock);
809 for(i = 0; i < 0x100; i++)
810 {
811 cfg.fakecws[i].count = 0;
812 NULLFREE(cfg.fakecws[i].data);
813 }
814 cs_writeunlock(__func__, &config_lock);
815
816 fp = open_config_file(cs_fakecws);
817 if(!fp)
818 { return 0; }
819
820 if(!cs_malloc(&token, MAXLINESIZE))
821 { return 0; }
822
823 while(fgets(token, MAXLINESIZE, fp))
824 {
825 if(sscanf(token, " %62s ", cw_string) == 1)
826 {
827 if(cs_strlen(cw_string) == 32)
828 {
829 if(cs_atob(cw, cw_string, 16) == 16)
830 {
831 wrong_checksum = 0;
832
833 for(i = 0; i < 16; i += 4)
834 {
835 c = ((cw[i] + cw[i + 1] + cw[i + 2]) & 0xff);
836 if(cw[i + 3] != c)
837 {
838 wrong_checksum = 1;
839 }
840 }
841
842 if(wrong_checksum)
843 {
844 cs_log("skipping fake cw %s because of wrong checksum!", cw_string);
845 }
846 else
847 {
848 idx = ((cw[0] & 0xF) << 4) | (cw[8] & 0xF);
849 alloccount[idx]++;
850 have_fakecw = 1;
851 }
852 }
853 else
854 {
855 cs_log("skipping fake cw %s because it contains invalid characters!", cw_string);
856 }
857 }
858 else
859 {
860 cs_log("skipping fake cw %s because of wrong length (%u != 32)!", cw_string, (uint32_t)cs_strlen(cw_string));
861 }
862 }
863 }
864
865 if(!have_fakecw)
866 {
867 NULLFREE(token);
868 fclose(fp);
869 return 0;
870 }
871
872 for(i = 0; i < 0x100; i++)
873 {
874 if(alloccount[i] && !cs_malloc(&cfg.fakecws[i].data, sizeof(struct s_cw)*alloccount[i]))
875 {
876 alloccount[i] = 0;
877 }
878 }
879
880 fseek(fp, 0, SEEK_SET);
881
882 while(fgets(token, MAXLINESIZE, fp))
883 {
884 if(sscanf(token, " %62s ", cw_string) == 1)
885 {
886 if(cs_strlen(cw_string) == 32)
887 {
888 if(cs_atob(cw, cw_string, 16) == 16)
889 {
890 wrong_checksum = 0;
891
892 for(i = 0; i < 16; i += 4)
893 {
894 c = ((cw[i] + cw[i + 1] + cw[i + 2]) & 0xff);
895 if(cw[i + 3] != c)
896 {
897 wrong_checksum = 1;
898 }
899 }
900
901 if(!wrong_checksum)
902 {
903 idx = ((cw[0] & 0xF) << 4) | (cw[8] & 0xF);
904
905 if(count[idx] < alloccount[idx])
906 {
907 memcpy(cfg.fakecws[idx].data[count[idx]].cw, cw, 16);
908 count[idx]++;
909 nr++;
910 }
911 }
912 }
913 }
914 }
915 }
916
917 NULLFREE(token);
918 fclose(fp);
919
920 if(nr > 0)
921 { cs_log("%d fakecws's loaded", nr); }
922
923
924 cs_writelock(__func__, &config_lock);
925 for(i = 0; i < 0x100; i++)
926 {
927 cfg.fakecws[i].count = count[i];
928 }
929 cs_writeunlock(__func__, &config_lock);
930
931
932 for(i = 0; i < 0x100; i++)
933 {
934 if(count[i] > max_compares)
935 { max_compares = count[i]; }
936 }
937
938 for(i = 0; i < (0x100 - 1); i++)
939 {
940 for(j = i + 1; j < 0x100; j++)
941 {
942 if(count[j] < count[i])
943 {
944 tmp = count[i];
945 count[i] = count[j];
946 count[j] = tmp;
947 }
948 }
949 }
950 average_compares = ((count[0x100 / 2] + count[0x100 / 2 - 1]) / 2);
951
952
953 cs_log("max %d fakecw compares required, on average: %d compares", max_compares, average_compares);
954
955 return 0;
956}
957
958static struct s_rlimit *ratelimit_read_int(void)
959{
960 FILE *fp = open_config_file(cs_ratelimit);
961 if(!fp)
962 { return NULL; }
963 char token[1024], str1[1024];
964 int32_t i, ret, count = 0;
965 struct s_rlimit *new_rlimit = NULL, *entry, *last = NULL;
966 uint32_t line = 0;
967
968 while(fgets(token, sizeof(token), fp))
969 {
970 line++;
971 if(cs_strlen(token) <= 1) { continue; }
972 if(token[0] == '#' || token[0] == '/') { continue; }
973 if(cs_strlen(token) > 1024) { continue; }
974
975 for(i = 0; i < (int)cs_strlen(token); i++)
976 {
977 if((token[i] == ':' || token[i] == ' ') && token[i + 1] == ':')
978 {
979 memmove(token + i + 2, token + i + 1, cs_strlen(token) - i + 1);
980 token[i + 1] = '0';
981 }
982 if(token[i] == '#' || token[i] == '/')
983 {
984 token[i] = '\0';
985 break;
986 }
987 }
988
989 caid = 0;
990 uint32_t provid = 0, srvid = 0, chid = 0, ratelimitecm = 0, ratelimittime = 0, srvidholdtime = 0;
991 memset(str1, 0, sizeof(str1));
992
993 ret = sscanf(token, "%4x:%6x:%4x:%4x:%d:%d:%d:%1023s", &caid, &provid, &srvid, &chid, &ratelimitecm, &ratelimittime, &srvidholdtime, str1);
994 if(ret < 1) {
995 continue;
996 }
997
998 if (!cs_strncat(str1, ",", sizeof(str1))) {
999 return new_rlimit;
1000 }
1001
1002 if(!cs_malloc(&entry, sizeof(struct s_rlimit)))
1003 {
1004 fclose(fp);
1005 return new_rlimit;
1006 }
1007
1008 count++;
1009 if (ratelimittime < 60) ratelimittime *= 1000;
1010 if (srvidholdtime < 60) srvidholdtime *= 1000;
1011 entry->rl.caid = caid;
1012 entry->rl.provid = provid;
1013 entry->rl.srvid = srvid;
1014 entry->rl.chid = chid;
1015 entry->rl.ratelimitecm = ratelimitecm;
1016 entry->rl.ratelimittime = ratelimittime;
1017 entry->rl.srvidholdtime = srvidholdtime;
1018
1019 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,
1020 entry->rl.ratelimitecm, entry->rl.ratelimittime, entry->rl.srvidholdtime);
1021
1022 if(!new_rlimit)
1023 {
1024 new_rlimit = entry;
1025 last = new_rlimit;
1026 }
1027 else
1028 {
1029 last->next = entry;
1030 last = entry;
1031 }
1032 }
1033
1034 if(count)
1035 { cs_log("%d entries read from %s", count, cs_ratelimit); }
1036
1037 fclose(fp);
1038
1039 return new_rlimit;
1040}
1041
1042void ratelimit_read(void)
1043{
1044
1045 struct s_rlimit *entry, *old_list;
1046
1047 old_list = cfg.ratelimit_list;
1048 cfg.ratelimit_list = ratelimit_read_int();
1049
1050 while(old_list)
1051 {
1052 entry = old_list->next;
1053 NULLFREE(old_list);
1054 old_list = entry;
1055 }
1056}
1057
1058struct ecmrl get_ratelimit(ECM_REQUEST *er)
1059{
1060
1061 struct ecmrl tmp;
1062 memset(&tmp, 0, sizeof(tmp));
1063 if(!cfg.ratelimit_list) { return tmp; }
1064 struct s_rlimit *entry = cfg.ratelimit_list;
1065 while(entry)
1066 {
1067 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 {
1069 break;
1070 }
1071 entry = entry->next;
1072 }
1073
1074 if(entry) { tmp = entry->rl; }
1075
1076 return (tmp);
1077}
1078
1079int32_t init_tierid(void)
1080{
1081 FILE *fp = open_config_file(cs_trid);
1082 if(!fp)
1083 { return 0; }
1084
1085 int32_t nr;
1086 char *payload, *saveptr1 = NULL, *token;
1087 if(!cs_malloc(&token, MAXLINESIZE))
1088 { return 0; }
1089 static struct s_tierid *tierid = NULL, *new_cfg_tierid = NULL;
1090
1091 nr = 0;
1092 while(fgets(token, MAXLINESIZE, fp))
1093 {
1094 void *ptr;
1095 char *tmp, *tieridasc;
1096 tmp = trim(token);
1097
1098 if(tmp[0] == '#') { continue; }
1099 if(cs_strlen(tmp) < 6) { continue; }
1100 if(!(payload = strchr(token, '|'))) { continue; }
1101 if(!(tieridasc = strchr(token, ':'))) { continue; }
1102 *payload++ = '\0';
1103
1104 if(!cs_malloc(&ptr, sizeof(struct s_tierid)))
1105 {
1106 NULLFREE(token);
1107 fclose(fp);
1108 return (1);
1109 }
1110 if(tierid)
1111 { tierid->next = ptr; }
1112 else
1113 { new_cfg_tierid = ptr; }
1114
1115 tierid = ptr;
1116
1117 int32_t i;
1118 char *ptr1 = strtok_r(payload, "|", &saveptr1);
1119 if(ptr1)
1120 { cs_strncpy(tierid->name, trim(ptr1), sizeof(tierid->name)); }
1121
1122 *tieridasc++ = '\0';
1123 tierid->tierid = dyn_word_atob(tieridasc);
1124 //printf("tierid %s - %d\n",tieridasc,tierid->tierid );
1125
1126 tierid->ncaid = 0;
1127 for(i = 0, ptr1 = strtok_r(token, ",", &saveptr1); (ptr1) && (i < 10) ; ptr1 = strtok_r(NULL, ",", &saveptr1), i++)
1128 {
1129 tierid->caid[i] = dyn_word_atob(ptr1);
1130 tierid->ncaid = i + 1;
1131 //cs_log("ld caid: %04X tierid: %04X name: %s",tierid->caid[i],tierid->tierid,tierid->name);
1132 }
1133 nr++;
1134 }
1135 NULLFREE(token);
1136 fclose(fp);
1137 if(nr > 0)
1138 { cs_log("%d tier-id's loaded", nr); }
1139 cs_writelock(__func__, &config_lock);
1140 // reload function:
1141 tierid = cfg.tierid;
1142 cfg.tierid = new_cfg_tierid;
1143 struct s_tierid *ptr;
1144 while(tierid)
1145 {
1146 ptr = tierid->next;
1147 NULLFREE(tierid);
1148 tierid = ptr;
1149 }
1150 cs_writeunlock(__func__, &config_lock);
1151
1152 return (0);
1153}
1154
1155int32_t match_whitelist(ECM_REQUEST *er, struct s_global_whitelist *entry)
1156{
1157 return ((!entry->caid || entry->caid == er->caid)
1158 && (!entry->provid || entry->provid == er->prid)
1159 && (!entry->srvid || entry->srvid == er->srvid)
1160 && (!entry->chid || entry->chid == er->chid)
1161 && (!entry->pid || entry->pid == er->pid)
1162 && (!entry->ecmlen || entry->ecmlen == er->ecmlen));
1163}
1164
1165int32_t chk_global_whitelist(ECM_REQUEST *er, uint32_t *line)
1166{
1167 *line = -1;
1168 if(!cfg.global_whitelist)
1169 { return 1; }
1170
1171 struct s_global_whitelist *entry;
1172
1173 // check mapping:
1174 if(cfg.global_whitelist_use_m)
1175 {
1176 entry = cfg.global_whitelist;
1177 while(entry)
1178 {
1179 if(entry->type == 'm')
1180 {
1181 if(match_whitelist(er, entry))
1182 {
1183 cs_log_dbg(D_TRACE, "whitelist: mapped %04X@%06X to %04X@%06X", er->caid, er->prid, entry->mapcaid, entry->mapprovid);
1184 er->caid = entry->mapcaid;
1185 er->prid = entry->mapprovid;
1186 break;
1187 }
1188 }
1189 entry = entry->next;
1190 }
1191 }
1192
1193 if(cfg.global_whitelist_use_l) // Check caid/prov/srvid etc matching, except ecm-len:
1194 {
1195 entry = cfg.global_whitelist;
1196 int8_t caidprov_matches = 0;
1197 while(entry)
1198 {
1199 if(entry->type == 'l')
1200 {
1201 if(match_whitelist(er, entry))
1202 {
1203 *line = entry->line;
1204 return 1;
1205 }
1206 if((!entry->caid || entry->caid == er->caid)
1207 && (!entry->provid || entry->provid == er->prid)
1208 && (!entry->srvid || entry->srvid == er->srvid)
1209 && (!entry->chid || entry->chid == er->chid)
1210 && (!entry->pid || entry->pid == er->pid))
1211 {
1212 caidprov_matches = 1;
1213 *line = entry->line;
1214 }
1215 }
1216 entry = entry->next;
1217 }
1218 if(caidprov_matches) // ...but not ecm-len!
1219 { return 0; }
1220 }
1221
1222 entry = cfg.global_whitelist;
1223 while(entry)
1224 {
1225 if(match_whitelist(er, entry))
1226 {
1227 *line = entry->line;
1228 if(entry->type == 'w')
1229 { return 1; }
1230 else if(entry->type == 'i')
1231 { return 0; }
1232 }
1233 entry = entry->next;
1234 }
1235 return 0;
1236}
1237
1238//Format:
1239//Whitelist-Entry:
1240//w:caid:prov:srvid:pid:chid:ecmlen
1241//Ignore-Entry:
1242//i:caid:prov:srvid:pid:chid:ecmlen
1243//ECM len check - Entry:
1244//l:caid:prov:srvid:pid:chid:ecmlen
1245
1246//Mapping:
1247//m:caid:prov:srvid:pid:chid:ecmlen caidto:provto
1248
1249static struct s_global_whitelist *global_whitelist_read_int(void)
1250{
1251 FILE *fp = open_config_file(cs_whitelist);
1252 if(!fp)
1253 { return NULL; }
1254
1255 char token[1024], str1[1024];
1256 uint8_t type;
1257 int32_t i, ret, count = 0;
1258 struct s_global_whitelist *new_whitelist = NULL, *entry, *last = NULL;
1259 uint32_t line = 0;
1260
1261 cfg.global_whitelist_use_l = 0;
1262 cfg.global_whitelist_use_m = 0;
1263
1264 while(fgets(token, sizeof(token), fp))
1265 {
1266 line++;
1267 if(cs_strlen(token) <= 1) { continue; }
1268 if(token[0] == '#' || token[0] == '/') { continue; }
1269 if(cs_strlen(token) > 1024) { continue; }
1270
1271 for(i = 0; i < (int)cs_strlen(token); i++)
1272 {
1273 if((token[i] == ':' || token[i] == ' ') && token[i + 1] == ':')
1274 {
1275 memmove(token + i + 2, token + i + 1, cs_strlen(token) - i + 1);
1276 token[i + 1] = '0';
1277 }
1278 if(token[i] == '#' || token[i] == '/')
1279 {
1280 token[i] = '\0';
1281 break;
1282 }
1283 }
1284
1285 type = 'w';
1286 caid = 0;
1287 uint32_t provid = 0, srvid = 0, pid = 0, chid = 0, ecmlen = 0, mapcaid = 0, mapprovid = 0;
1288 memset(str1, 0, sizeof(str1));
1289
1290 ret = sscanf(token, "%c:%4x:%6x:%4x:%4x:%4x:%1023s", &type, &caid, &provid, &srvid, &pid, &chid, str1);
1291
1292 type = tolower(type);
1293
1294 //w=whitelist
1295 //i=ignore
1296 //l=len-check
1297 //m=map caid/prov
1298 if(ret < 1 || (type != 'w' && type != 'i' && type != 'l' && type != 'm'))
1299 { continue; }
1300
1301 if(type == 'm')
1302 {
1303 char *p = strstr(token + 4, " ");
1304 if(!p || sscanf(p + 1, "%4x:%6x", &mapcaid, &mapprovid) < 2)
1305 {
1306 cs_log_dbg(D_TRACE, "whitelist: wrong mapping: %s", token);
1307 continue;
1308 }
1309 str1[0] = 0;
1310 cfg.global_whitelist_use_m = 1;
1311 }
1312
1313 if (!cs_strncat(str1, ",", sizeof(str1))) {
1314 return new_whitelist;
1315 }
1316
1317 char *p = str1, *p2 = str1;
1318
1319 while(*p)
1320 {
1321 if(*p == ',')
1322 {
1323 *p = 0;
1324 ecmlen = 0;
1325 sscanf(p2, "%4x", &ecmlen);
1326
1327 if(!cs_malloc(&entry, sizeof(struct s_global_whitelist)))
1328 {
1329 fclose(fp);
1330 return new_whitelist;
1331 }
1332
1333 count++;
1334 entry->line = line;
1335 entry->type = type;
1336 entry->caid = caid;
1337 entry->provid = provid;
1338 entry->srvid = srvid;
1339 entry->pid = pid;
1340 entry->chid = chid;
1341 entry->ecmlen = ecmlen;
1342 entry->mapcaid = mapcaid;
1343 entry->mapprovid = mapprovid;
1344 if(entry->type == 'l')
1345 { cfg.global_whitelist_use_l = 1; }
1346
1347 if(type == 'm')
1348 cs_log_dbg(D_TRACE, "whitelist: %c: %04X@%06X:%04X:%04X:%04X:%02X map to %04X@%06X",
1349 entry->type, entry->caid, entry->provid, entry->srvid, entry->pid, entry->chid, entry->ecmlen, entry->mapcaid, entry->mapprovid);
1350 else
1351 cs_log_dbg(D_TRACE, "whitelist: %c: %04X@%06X:%04X:%04X:%04X:%02X",
1352 entry->type, entry->caid, entry->provid, entry->srvid, entry->pid, entry->chid, entry->ecmlen);
1353
1354 if(!new_whitelist)
1355 {
1356 new_whitelist = entry;
1357 last = new_whitelist;
1358 }
1359 else
1360 {
1361 last->next = entry;
1362 last = entry;
1363 }
1364
1365 p2 = p + 1;
1366 }
1367 p++;
1368 }
1369 }
1370
1371 if(count)
1372 { cs_log("%d entries read from %s", count, cs_whitelist); }
1373
1374 fclose(fp);
1375
1376 return new_whitelist;
1377}
1378
1379void global_whitelist_read(void)
1380{
1381 struct s_global_whitelist *entry, *old_list;
1382
1383 old_list = cfg.global_whitelist;
1384 cfg.global_whitelist = global_whitelist_read_int();
1385
1386 while(old_list)
1387 {
1388 entry = old_list->next;
1389 NULLFREE(old_list);
1390 old_list = entry;
1391 }
1392}
1393
1394void init_len4caid(void)
1395{
1396 FILE *fp = open_config_file(cs_l4ca);
1397 if(!fp)
1398 { return; }
1399
1400 int32_t nr;
1401 char *value, *token;
1402
1403 if(!cs_malloc(&token, MAXLINESIZE))
1404 { return; }
1405
1406 memset(len4caid, 0, sizeof(uint16_t) << 8);
1407 for(nr = 0; fgets(token, MAXLINESIZE, fp);)
1408 {
1409 int32_t i, c;
1410 char *ptr;
1411 if(!(value = strchr(token, ':')))
1412 { continue; }
1413 *value++ = '\0';
1414 if((ptr = strchr(value, '#')))
1415 { * ptr = '\0'; }
1416 if(cs_strlen(trim(token)) != 2)
1417 { continue; }
1418 if(cs_strlen(trim(value)) != 4)
1419 { continue; }
1420 if((i = byte_atob(token)) < 0)
1421 { continue; }
1422 if((c = word_atob(value)) < 0)
1423 { continue; }
1424 len4caid[i] = c;
1425 nr++;
1426 }
1427 NULLFREE(token);
1428 fclose(fp);
1429 if(nr)
1430 { cs_log("%d lengths for caid guessing loaded", nr); }
1431 return;
1432}
1433
1434#ifdef MODULE_SERIAL
1435static struct s_twin *twin_read_int(void)
1436{
1437 FILE *fp = open_config_file(cs_twin);
1438 if(!fp)
1439 { return NULL; }
1440 char token[1024], str1[1024];
1441 int32_t i, ret, count = 0;
1442 struct s_twin *new_twin = NULL, *entry, *last = NULL;
1443 uint32_t line = 0;
1444
1445 while(fgets(token, sizeof(token), fp))
1446 {
1447 line++;
1448 if(cs_strlen(token) <= 1) { continue; }
1449 if(token[0] == '#' || token[0] == '/') { continue; }
1450 if(cs_strlen(token) > 1024) { continue; }
1451
1452 for(i = 0; i < (int)cs_strlen(token); i++)
1453 {
1454 if((token[i] == ':' || token[i] == ' ') && token[i + 1] == ':')
1455 {
1456 memmove(token + i + 2, token + i + 1, cs_strlen(token) - i + 1);
1457 token[i + 1] = '0';
1458 }
1459 if(token[i] == '#' || token[i] == '/' || token[i] == '"')
1460 {
1461 token[i] = '\0';
1462 break;
1463 }
1464 }
1465
1466 caid = 0;
1467 uint32_t provid = 0, srvid = 0, deg = 0, freq = 0;
1468 //char hdeg[4], hfreq[4], hsrvid[4];
1469 memset(str1, 0, sizeof(str1));
1470
1471 ret = sscanf(token, "%4x:%6x:%d:%d:%d", &caid, &provid, &deg, &freq, &srvid);
1472 if(ret < 1) { continue; }
1473
1474 //snprintf(hdeg, 4, "%x", deg);
1475 //sscanf(hdeg, "%4x", &deg);
1476 //snprintf(hfreq, 4, "%x", freq);
1477 //sscanf(hfreq, "%4x", &freq);
1478 //snprintf(hsrvid, 4, "%x", srvid);
1479 //sscanf(hsrvid, "%4x", &srvid);
1480 if (!cs_strncat(str1, ",", sizeof(str1))) {
1481 return new_twin;
1482 }
1483
1484 if(!cs_malloc(&entry, sizeof(struct s_twin)))
1485 {
1486 fclose(fp);
1487 return new_twin;
1488 }
1489
1490 count++;
1491 entry->tw.caid = caid;
1492 entry->tw.provid = provid;
1493 entry->tw.srvid = srvid;
1494 entry->tw.deg = deg;
1495 entry->tw.freq = freq;
1496
1497 cs_debug_mask(D_TRACE, "channel: %04X:%06X:%d:%d:%d", entry->tw.caid,
1498 entry->tw.provid, entry->tw.deg, entry->tw.freq, entry->tw.srvid);
1499
1500 if(!new_twin)
1501 {
1502 new_twin = entry;
1503 last = new_twin;
1504 }
1505 else
1506 {
1507 last->next = entry;
1508 last = entry;
1509 }
1510 }
1511
1512 if(count)
1513 { cs_log("%d entries read from %s", count, cs_twin); }
1514
1515 fclose(fp);
1516
1517 return new_twin;
1518}
1519
1520void twin_read(void)
1521{
1522
1523 struct s_twin *entry, *old_list;
1524
1525 old_list = cfg.twin_list;
1526 cfg.twin_list = twin_read_int();
1527
1528 while(old_list)
1529 {
1530 entry = old_list->next;
1531 free(old_list);
1532 old_list = entry;
1533 }
1534}
1535
1536struct ecmtw get_twin(ECM_REQUEST *er)
1537{
1538 struct ecmtw tmp;
1539 memset(&tmp, 0, sizeof(tmp));
1540 if(!cfg.twin_list)
1541 {
1542 cs_log("twin_list not found!");
1543 return tmp;
1544 }
1545 struct s_twin *entry = cfg.twin_list;
1546 while(entry)
1547 {
1548 if(entry->tw.caid == er->caid && entry->tw.provid == er->prid && entry->tw.srvid == er->srvid)
1549 {
1550 break;
1551 }
1552 entry = entry->next;
1553 }
1554
1555 if(entry) { tmp = entry->tw; }
1556
1557 return (tmp);
1558}
1559#endif
Note: See TracBrowser for help on using the repository browser.