1 | #define MODULE_LOG_PREFIX "emmcache"
|
---|
2 |
|
---|
3 | #include "globals.h"
|
---|
4 | #include "oscam-config.h"
|
---|
5 | #include "oscam-string.h"
|
---|
6 | #include "oscam-emm-cache.h"
|
---|
7 | #include "oscam-files.h"
|
---|
8 | #include "oscam-time.h"
|
---|
9 | #include "oscam-lock.h"
|
---|
10 | #include "cscrypt/md5.h"
|
---|
11 | #define LINESIZE 1024
|
---|
12 | #define DEFAULT_LOCK_TIMEOUT 1000000
|
---|
13 |
|
---|
14 | static LLIST *emm_cache;
|
---|
15 |
|
---|
16 | bool emm_cache_configured(void)
|
---|
17 | {
|
---|
18 | struct s_reader *rdr;
|
---|
19 | bool enable = false;
|
---|
20 | LL_ITER itr = ll_iter_create(configured_readers);
|
---|
21 | while((rdr = ll_iter_next(&itr)))
|
---|
22 | {
|
---|
23 | if(rdr->cachemm == 1)
|
---|
24 | {
|
---|
25 | enable = true;
|
---|
26 | }
|
---|
27 | }
|
---|
28 | return enable;
|
---|
29 | }
|
---|
30 |
|
---|
31 | void emm_save_cache(void)
|
---|
32 | {
|
---|
33 | if(boxtype_is("dbox2")) return; // dont save emmcache on these boxes, they lack resources and will crash!
|
---|
34 |
|
---|
35 | if(!emm_cache_configured()){
|
---|
36 | cs_log("saving emmcache disabled since no reader is using it!");
|
---|
37 | return;
|
---|
38 | }
|
---|
39 |
|
---|
40 | char fname[256];
|
---|
41 | struct timeb ts, te;
|
---|
42 |
|
---|
43 | if(!cfg.emmlogdir)
|
---|
44 | {
|
---|
45 | get_tmp_dir_filename(fname, sizeof(fname), "oscam.emmcache");
|
---|
46 | }
|
---|
47 | else
|
---|
48 | {
|
---|
49 | get_config_filename(fname, sizeof(fname), "oscam.emmcache");
|
---|
50 | }
|
---|
51 | FILE *file = fopen(fname, "w");
|
---|
52 |
|
---|
53 | if(!file)
|
---|
54 | {
|
---|
55 | cs_log("can't write emmcache to file %s", fname);
|
---|
56 | return;
|
---|
57 | }
|
---|
58 |
|
---|
59 | cs_ftime(&ts);
|
---|
60 | int32_t count = 0, result = 0;
|
---|
61 | LL_ITER it = ll_iter_create(emm_cache);
|
---|
62 | struct s_emmcache *c;
|
---|
63 | while((c = ll_iter_next(&it)))
|
---|
64 | {
|
---|
65 | uchar tmp_emmd5[MD5_DIGEST_LENGTH * 2 + 1];
|
---|
66 | char_to_hex(c->emmd5, MD5_DIGEST_LENGTH, tmp_emmd5);
|
---|
67 | uchar tmp_emm[c->len * 2 + 1];
|
---|
68 | char_to_hex(c->emm, c->len, tmp_emm);
|
---|
69 | result = fprintf(file, "%s,%ld,%ld,%02X,%04X,%s\n", tmp_emmd5, c->firstseen.time, c->lastseen.time, c->type, c->len, tmp_emm);
|
---|
70 | if(result < 0)
|
---|
71 | {
|
---|
72 | fclose(file);
|
---|
73 | result = remove(fname);
|
---|
74 | if(!result)
|
---|
75 | {
|
---|
76 | cs_log("error writing cache -> cache file removed!");
|
---|
77 | }
|
---|
78 | else
|
---|
79 | {
|
---|
80 | cs_log("error writing cache -> cache file could not be removed either!");
|
---|
81 | }
|
---|
82 | return;
|
---|
83 | }
|
---|
84 | count++;
|
---|
85 | }
|
---|
86 |
|
---|
87 | fclose(file);
|
---|
88 | cs_ftime(&te);
|
---|
89 | int64_t load_time = comp_timeb(&te, &ts);
|
---|
90 | cs_log("saved %d emmcache records to %s in %"PRId64" ms", count, fname, load_time);
|
---|
91 | }
|
---|
92 |
|
---|
93 | void load_emmstat_from_file(void)
|
---|
94 | {
|
---|
95 | if(boxtype_is("dbox2")) return; // dont load emmstat on these boxes, they lack resources and will crash!
|
---|
96 |
|
---|
97 | if(!emm_cache_configured()){
|
---|
98 | cs_log("loading emmstats disabled since no reader is using it!");
|
---|
99 | return;
|
---|
100 | }
|
---|
101 |
|
---|
102 | char buf[256];
|
---|
103 | char fname[256];
|
---|
104 | char *line;
|
---|
105 | FILE *file;
|
---|
106 |
|
---|
107 | if(!cfg.emmlogdir)
|
---|
108 | {
|
---|
109 | get_tmp_dir_filename(fname, sizeof(fname), "oscam.emmstat");
|
---|
110 | }
|
---|
111 | else
|
---|
112 | {
|
---|
113 | get_config_filename(fname, sizeof(fname), "oscam.emmstat");
|
---|
114 | }
|
---|
115 | file = fopen(fname, "r");
|
---|
116 | if(!file)
|
---|
117 | {
|
---|
118 | cs_log_dbg(D_TRACE, "can't read emmstats from file %s", fname);
|
---|
119 | return;
|
---|
120 | }
|
---|
121 |
|
---|
122 | if(!cs_malloc(&line, LINESIZE))
|
---|
123 | {
|
---|
124 | fclose(file);
|
---|
125 | return;
|
---|
126 | }
|
---|
127 |
|
---|
128 | struct timeb ts, te;
|
---|
129 | cs_ftime(&ts);
|
---|
130 |
|
---|
131 | struct s_reader *rdr = NULL;
|
---|
132 | struct s_emmstat *s;
|
---|
133 |
|
---|
134 | int32_t i = 1;
|
---|
135 | int32_t valid = 0;
|
---|
136 | int32_t count = 0;
|
---|
137 | char *ptr, *saveptr1 = NULL;
|
---|
138 | char *split[7];
|
---|
139 |
|
---|
140 | while(fgets(line, LINESIZE, file))
|
---|
141 | {
|
---|
142 | if(!line[0] || line[0] == '#' || line[0] == ';')
|
---|
143 | { continue; }
|
---|
144 |
|
---|
145 | if(!cs_malloc(&s, sizeof(struct s_emmstat)))
|
---|
146 | { continue; }
|
---|
147 |
|
---|
148 | for(i = 0, ptr = strtok_r(line, ",", &saveptr1); ptr && i < 7 ; ptr = strtok_r(NULL, ",", &saveptr1), i++)
|
---|
149 | { split[i] = ptr; }
|
---|
150 | valid = (i == 6);
|
---|
151 | if(valid)
|
---|
152 | {
|
---|
153 | strncpy(buf, split[0], sizeof(buf) - 1);
|
---|
154 | key_atob_l(split[1], s->emmd5, MD5_DIGEST_LENGTH*2);
|
---|
155 | s->firstwritten.time = atol(split[2]);
|
---|
156 | s->lastwritten.time = atol(split[3]);
|
---|
157 | s->type = a2i(split[4], 2);
|
---|
158 | s->count = a2i(split[5], 4);
|
---|
159 |
|
---|
160 | LL_ITER itr = ll_iter_create(configured_readers);
|
---|
161 |
|
---|
162 | while((rdr = ll_iter_next(&itr)))
|
---|
163 | {
|
---|
164 | if(rdr->cachemm !=1) //skip: emmcache save is disabled
|
---|
165 | {
|
---|
166 | continue;
|
---|
167 | }
|
---|
168 | if(strcmp(rdr->label, buf) == 0)
|
---|
169 | {
|
---|
170 | break;
|
---|
171 | }
|
---|
172 | }
|
---|
173 |
|
---|
174 | if(rdr != NULL)
|
---|
175 | {
|
---|
176 | if(!rdr->emmstat)
|
---|
177 | {
|
---|
178 | rdr->emmstat = ll_create("emmstat");
|
---|
179 | cs_lock_create(&rdr->emmstat_lock, rdr->label, DEFAULT_LOCK_TIMEOUT);
|
---|
180 | }
|
---|
181 |
|
---|
182 | ll_append(rdr->emmstat, s);
|
---|
183 | count++;
|
---|
184 | }
|
---|
185 | else
|
---|
186 | {
|
---|
187 | cs_log("emmstats could not be loaded for %s", buf);
|
---|
188 | NULLFREE(s);
|
---|
189 | }
|
---|
190 | }
|
---|
191 | else
|
---|
192 | {
|
---|
193 | cs_log_dbg(D_EMM, "emmstat ERROR: %s count=%d type=%d", buf, s->count, s->type);
|
---|
194 | NULLFREE(s);
|
---|
195 | }
|
---|
196 | }
|
---|
197 |
|
---|
198 | fclose(file);
|
---|
199 | NULLFREE(line);
|
---|
200 |
|
---|
201 | cs_ftime(&te);
|
---|
202 | int64_t load_time = comp_timeb(&te, &ts);
|
---|
203 | cs_log("loaded %d emmstat records from %s in %"PRId64" ms", count, fname, load_time);
|
---|
204 | }
|
---|
205 |
|
---|
206 | void save_emmstat_to_file(void)
|
---|
207 | {
|
---|
208 | if(boxtype_is("dbox2")) return; // dont save emmstat on these boxes, they lack resources and will crash!
|
---|
209 |
|
---|
210 | if(!emm_cache_configured()){
|
---|
211 | cs_log("saving emmstats disabled since no reader is using it!");
|
---|
212 | return;
|
---|
213 | }
|
---|
214 |
|
---|
215 | char fname[256];
|
---|
216 |
|
---|
217 | if(!cfg.emmlogdir)
|
---|
218 | {
|
---|
219 | get_tmp_dir_filename(fname, sizeof(fname), "oscam.emmstat");
|
---|
220 | }
|
---|
221 | else
|
---|
222 | {
|
---|
223 | get_config_filename(fname, sizeof(fname), "oscam.emmstat");
|
---|
224 | }
|
---|
225 | FILE *file = fopen(fname, "w");
|
---|
226 |
|
---|
227 | if(!file)
|
---|
228 | {
|
---|
229 | cs_log("can't write to file %s", fname);
|
---|
230 | return;
|
---|
231 | }
|
---|
232 |
|
---|
233 | struct timeb ts, te;
|
---|
234 | cs_ftime(&ts);
|
---|
235 |
|
---|
236 | int32_t count = 0, result = 0;
|
---|
237 | struct s_reader *rdr;
|
---|
238 | LL_ITER itr = ll_iter_create(configured_readers);
|
---|
239 | while((rdr = ll_iter_next(&itr)))
|
---|
240 | {
|
---|
241 | if(!rdr->cachemm || rdr->cachemm == 2)
|
---|
242 | {
|
---|
243 | cs_log("reader %s skipped since emmcache save is disabled", rdr->label);
|
---|
244 | continue;
|
---|
245 | }
|
---|
246 |
|
---|
247 | if(rdr->emmstat)
|
---|
248 | {
|
---|
249 | cs_writelock(&rdr->emmstat_lock);
|
---|
250 | LL_ITER it = ll_iter_create(rdr->emmstat);
|
---|
251 | struct s_emmstat *s;
|
---|
252 | while((s = ll_iter_next(&it)))
|
---|
253 | {
|
---|
254 | uchar tmp_emmd5[MD5_DIGEST_LENGTH * 2 + 1];
|
---|
255 | char_to_hex(s->emmd5, MD5_DIGEST_LENGTH, tmp_emmd5);
|
---|
256 | result = fprintf(file, "%s,%s,%ld,%ld,%02X,%04X\n", rdr->label, tmp_emmd5, s->firstwritten.time, s->lastwritten.time, s->type, s->count);
|
---|
257 | if(result < 0)
|
---|
258 | {
|
---|
259 | cs_writeunlock(&rdr->emmstat_lock);
|
---|
260 | fclose(file);
|
---|
261 | result = remove(fname);
|
---|
262 | if(!result)
|
---|
263 | {
|
---|
264 | cs_log("error writing stats -> stat file removed!");
|
---|
265 | }
|
---|
266 | else
|
---|
267 | {
|
---|
268 | cs_log("error writing stats -> stat file could not be removed either!");
|
---|
269 | }
|
---|
270 | return;
|
---|
271 | }
|
---|
272 | count++;
|
---|
273 | }
|
---|
274 | cs_writeunlock(&rdr->emmstat_lock);
|
---|
275 | }
|
---|
276 | }
|
---|
277 |
|
---|
278 | fclose(file);
|
---|
279 |
|
---|
280 | cs_ftime(&te);
|
---|
281 | int64_t load_time = comp_timeb(&te, &ts);
|
---|
282 |
|
---|
283 | cs_log("saved %d emmstat records to %s in %"PRId64" ms", count, fname, load_time);
|
---|
284 | }
|
---|
285 |
|
---|
286 | void emm_load_cache(void)
|
---|
287 | {
|
---|
288 | if(boxtype_is("dbox2")) return; // dont load emmcache on these boxes, they lack resources and will crash!
|
---|
289 |
|
---|
290 | if(!emm_cache_configured()){
|
---|
291 | cs_log("loading emmcache disabled since no reader is using it!");
|
---|
292 | return;
|
---|
293 | }
|
---|
294 |
|
---|
295 | char fname[256];
|
---|
296 | char line[1024];
|
---|
297 | FILE *file;
|
---|
298 | struct s_emmcache *c;
|
---|
299 |
|
---|
300 | if(!cfg.emmlogdir)
|
---|
301 | {
|
---|
302 | get_tmp_dir_filename(fname, sizeof(fname), "oscam.emmcache");
|
---|
303 | }
|
---|
304 | else
|
---|
305 | {
|
---|
306 | get_config_filename(fname, sizeof(fname), "oscam.emmcache");
|
---|
307 | }
|
---|
308 |
|
---|
309 | file = fopen(fname, "r");
|
---|
310 | if(!file)
|
---|
311 | {
|
---|
312 | cs_log_dbg(D_TRACE, "can't read emmcache from file %s", fname);
|
---|
313 | return;
|
---|
314 | }
|
---|
315 |
|
---|
316 | struct timeb ts, te;
|
---|
317 | cs_ftime(&ts);
|
---|
318 |
|
---|
319 | int32_t count = 0;
|
---|
320 | int32_t i = 1;
|
---|
321 | int32_t valid = 0;
|
---|
322 | char *ptr, *saveptr1 = NULL;
|
---|
323 | char *split[7];
|
---|
324 |
|
---|
325 | memset(line, 0, sizeof(line));
|
---|
326 | while(fgets(line, sizeof(line), file))
|
---|
327 | {
|
---|
328 | if(!line[0] || line[0] == '#' || line[0] == ';')
|
---|
329 | { continue; }
|
---|
330 |
|
---|
331 | for(i = 0, ptr = strtok_r(line, ",", &saveptr1); ptr && i < 7 ; ptr = strtok_r(NULL, ",", &saveptr1), i++)
|
---|
332 | {
|
---|
333 | split[i] = ptr;
|
---|
334 | }
|
---|
335 |
|
---|
336 | valid = (i == 6);
|
---|
337 | if(valid)
|
---|
338 | {
|
---|
339 | if(!cs_malloc(&c, sizeof(struct s_emmcache)))
|
---|
340 | { continue; }
|
---|
341 | key_atob_l(split[0], c->emmd5, MD5_DIGEST_LENGTH*2);
|
---|
342 | c->firstseen.time = atol(split[1]);
|
---|
343 | c->lastseen.time = atol(split[2]);
|
---|
344 | c->type = a2i(split[3], 2);
|
---|
345 | c->len = a2i(split[4], 4);
|
---|
346 | key_atob_l(split[5], c->emm, c->len*2);
|
---|
347 |
|
---|
348 | if(valid && c->len != 0)
|
---|
349 | {
|
---|
350 | if(!emm_cache)
|
---|
351 | {
|
---|
352 | emm_cache = ll_create("emm cache");
|
---|
353 | }
|
---|
354 |
|
---|
355 | ll_append(emm_cache, c);
|
---|
356 | count++;
|
---|
357 | }
|
---|
358 | else
|
---|
359 | {
|
---|
360 | NULLFREE(c);
|
---|
361 | }
|
---|
362 | }
|
---|
363 | }
|
---|
364 | fclose(file);
|
---|
365 | cs_ftime(&te);
|
---|
366 | int64_t load_time = comp_timeb(&te, &ts);
|
---|
367 | cs_log("loaded %d emmcache records from %s in %"PRId64" ms", count, fname, load_time);
|
---|
368 | }
|
---|
369 |
|
---|
370 | struct s_emmcache *find_emm_cache(uchar *emmd5)
|
---|
371 | {
|
---|
372 | struct s_emmcache *c;
|
---|
373 | LL_ITER it;
|
---|
374 |
|
---|
375 | if(!emm_cache)
|
---|
376 | { emm_cache = ll_create("emm cache"); }
|
---|
377 |
|
---|
378 | it = ll_iter_create(emm_cache);
|
---|
379 | while((c = ll_iter_next(&it)))
|
---|
380 | {
|
---|
381 | if(!memcmp(emmd5, c->emmd5, MD5_DIGEST_LENGTH))
|
---|
382 | {
|
---|
383 | cs_log_dump_dbg(D_EMM, c->emmd5, MD5_DIGEST_LENGTH, "found emmcache match");
|
---|
384 | return c;
|
---|
385 | }
|
---|
386 | }
|
---|
387 | return NULL;
|
---|
388 | }
|
---|
389 |
|
---|
390 | int32_t clean_stale_emm_cache_and_stat(uchar *emmd5, int64_t gone)
|
---|
391 | {
|
---|
392 | struct timeb now;
|
---|
393 | cs_ftime(&now);
|
---|
394 | int32_t count = 0;
|
---|
395 |
|
---|
396 | struct s_emmcache *c;
|
---|
397 | LL_ITER it;
|
---|
398 |
|
---|
399 | if(!emm_cache)
|
---|
400 | { emm_cache = ll_create("emm cache"); }
|
---|
401 |
|
---|
402 | it = ll_iter_create(emm_cache);
|
---|
403 | while((c = ll_iter_next(&it)))
|
---|
404 | {
|
---|
405 |
|
---|
406 | if(comp_timeb(&now, &c->lastseen) > gone && memcmp(c->emmd5, emmd5, MD5_DIGEST_LENGTH)) // clean older than gone ms and dont clean if its the current emm!
|
---|
407 | {
|
---|
408 | struct s_reader *rdr;
|
---|
409 | LL_ITER rdr_itr = ll_iter_create(configured_readers);
|
---|
410 | while((rdr = ll_iter_next(&rdr_itr)))
|
---|
411 | {
|
---|
412 | if(rdr->emmstat)
|
---|
413 | {
|
---|
414 | remove_emm_stat(rdr, c->emmd5); // clean stale entry from stats
|
---|
415 | count++;
|
---|
416 | }
|
---|
417 | }
|
---|
418 | ll_iter_remove_data(&it); // clean stale entry from emmcache
|
---|
419 | }
|
---|
420 | }
|
---|
421 | return count;
|
---|
422 | }
|
---|
423 |
|
---|
424 | int32_t emm_edit_cache(uchar *emmd5, EMM_PACKET *ep, bool add)
|
---|
425 | {
|
---|
426 | struct s_emmcache *c;
|
---|
427 | LL_ITER it;
|
---|
428 | int32_t count = 0;
|
---|
429 |
|
---|
430 | if(!emm_cache)
|
---|
431 | { emm_cache = ll_create("emm cache"); }
|
---|
432 |
|
---|
433 | it = ll_iter_create(emm_cache);
|
---|
434 | while((c = ll_iter_next(&it)))
|
---|
435 | {
|
---|
436 | if(!memcmp(emmd5, c->emmd5, MD5_DIGEST_LENGTH))
|
---|
437 | {
|
---|
438 | if(add)
|
---|
439 | {
|
---|
440 | return 0; //already added
|
---|
441 | }
|
---|
442 | ll_iter_remove_data(&it);
|
---|
443 | count++;
|
---|
444 | }
|
---|
445 | }
|
---|
446 |
|
---|
447 | if(add)
|
---|
448 | {
|
---|
449 | if(!cs_malloc(&c, sizeof(struct s_emmcache)))
|
---|
450 | { return count; }
|
---|
451 | memcpy(c->emmd5, emmd5, MD5_DIGEST_LENGTH);
|
---|
452 | c->type = ep->type;
|
---|
453 | c->len = ep->emm[2];
|
---|
454 | cs_ftime(&c->firstseen);
|
---|
455 | c->lastseen = c->firstseen;
|
---|
456 | memcpy(c->emm, ep->emm, c->len);
|
---|
457 | ll_append(emm_cache, c);
|
---|
458 | #ifdef WITH_DEBUG
|
---|
459 | cs_log_dump_dbg(D_EMM, c->emmd5, MD5_DIGEST_LENGTH, "added emm to cache:");
|
---|
460 | #endif
|
---|
461 | count++;
|
---|
462 | }
|
---|
463 |
|
---|
464 | return count;
|
---|
465 | }
|
---|
466 | int32_t remove_emm_stat(struct s_reader *rdr, uchar *emmd5)
|
---|
467 | {
|
---|
468 | int32_t count = 0;
|
---|
469 | if(rdr && rdr->emmstat)
|
---|
470 | {
|
---|
471 | cs_writelock(&rdr->emmstat_lock);
|
---|
472 | struct s_emmstat *c;
|
---|
473 | LL_ITER itr = ll_iter_create(rdr->emmstat);
|
---|
474 | while((c = ll_iter_next(&itr)))
|
---|
475 | {
|
---|
476 | if(!memcmp(emmd5, c->emmd5, MD5_DIGEST_LENGTH))
|
---|
477 | {
|
---|
478 | ll_iter_remove_data(&itr);
|
---|
479 | count++;
|
---|
480 | break;
|
---|
481 | }
|
---|
482 | }
|
---|
483 |
|
---|
484 | cs_writeunlock(&rdr->emmstat_lock);
|
---|
485 | }
|
---|
486 | return count;
|
---|
487 | }
|
---|
488 |
|
---|
489 | struct s_emmstat *get_emm_stat(struct s_reader *rdr, uchar *emmd5, uchar emmtype)
|
---|
490 | {
|
---|
491 | if(!rdr->cachemm) return NULL;
|
---|
492 |
|
---|
493 | struct s_emmstat *c;
|
---|
494 | LL_ITER it;
|
---|
495 |
|
---|
496 | if(!rdr->emmstat)
|
---|
497 | { rdr->emmstat = ll_create("emm stat"); }
|
---|
498 |
|
---|
499 | it = ll_iter_create(rdr->emmstat);
|
---|
500 | while((c = ll_iter_next(&it)))
|
---|
501 | {
|
---|
502 | if(!memcmp(emmd5, c->emmd5, MD5_DIGEST_LENGTH))
|
---|
503 | {
|
---|
504 | cs_log_dump_dbg(D_EMM, c->emmd5, MD5_DIGEST_LENGTH, "found emmstat match (reader:%s, count:%d)", rdr->label, c->count);
|
---|
505 | return c;
|
---|
506 | }
|
---|
507 | }
|
---|
508 |
|
---|
509 | if(cs_malloc(&c, sizeof(struct s_emmstat)))
|
---|
510 | {
|
---|
511 | memcpy(c->emmd5, emmd5, MD5_DIGEST_LENGTH);
|
---|
512 | c->type = emmtype;
|
---|
513 | ll_append(rdr->emmstat, c);
|
---|
514 | cs_log_dump_dbg(D_EMM, c->emmd5, MD5_DIGEST_LENGTH, "added emmstat (reader:%s, count:%d)", rdr->label, c->count);
|
---|
515 | }
|
---|
516 | return c;
|
---|
517 | }
|
---|