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 |
|
---|
16 | extern 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 |
|
---|
28 | uint32_t cfg_sidtab_generation = 1;
|
---|
29 | uint32_t caid;
|
---|
30 |
|
---|
31 | extern char cs_confdir[];
|
---|
32 |
|
---|
33 | char *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 |
|
---|
40 | int32_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 |
|
---|
93 | void 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 |
|
---|
102 | static 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 |
|
---|
182 | void 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 |
|
---|
225 | void 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
|
---|
240 | static 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
|
---|
268 | static void show_sidtab(struct s_sidtab *UNUSED(sidtab)) { }
|
---|
269 | #endif
|
---|
270 |
|
---|
271 | int32_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 |
|
---|
337 | int32_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 |
|
---|
479 | int32_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 |
|
---|
797 | int32_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 |
|
---|
958 | static 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 |
|
---|
1042 | void 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 |
|
---|
1058 | struct 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 |
|
---|
1079 | int32_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 |
|
---|
1155 | int32_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 |
|
---|
1165 | int32_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 |
|
---|
1249 | static 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 |
|
---|
1379 | void 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 |
|
---|
1394 | void 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
|
---|
1435 | static 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, °, &freq, &srvid);
|
---|
1472 | if(ret < 1) { continue; }
|
---|
1473 |
|
---|
1474 | //snprintf(hdeg, 4, "%x", deg);
|
---|
1475 | //sscanf(hdeg, "%4x", °);
|
---|
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 |
|
---|
1520 | void 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 |
|
---|
1536 | struct 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
|
---|