- fix Building without Nagra not possible at Nagra_Merlin https://trac.streamboard...
[oscam.git] / oscam-emm-cache.c
blob47c6f434871479cde144b874f320e9c9e4a94e8b
1 #define MODULE_LOG_PREFIX "emmcache"
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
14 static LLIST *emm_cache;
16 bool emm_cache_configured(void)
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)))
23 if(rdr->cachemm == 1)
25 enable = true;
28 return enable;
31 static char *get_emmcache_filename(char *dest, size_t destlen, const char *filename)
33 const char *slash = "";
34 if(cfg.emmlogdir[strlen(cfg.emmlogdir) - 1] != '/')
36 slash = "/";
38 snprintf(dest, destlen, "%s%s%s", cfg.emmlogdir, slash, filename);
39 return dest;
42 void emm_save_cache(void)
44 if(boxtype_is("dbox2")) return; // don't save emmcache on these boxes, they lack resources and will crash!
46 if(!emm_cache_configured()){
47 cs_log("saving emmcache disabled since no reader is using it!");
48 return;
51 char fname[256];
52 struct timeb ts, te;
54 if(cfg.emmlogdir)
56 get_emmcache_filename(fname, sizeof(fname), "oscam.emmcache");
58 else
60 get_config_filename(fname, sizeof(fname), "oscam.emmcache");
62 FILE *file = fopen(fname, "w");
64 if(!file)
66 cs_log("can't write emmcache to file %s", fname);
67 return;
70 cs_ftime(&ts);
71 int32_t count = 0, result = 0;
72 LL_ITER it = ll_iter_create(emm_cache);
73 struct s_emmcache *c;
75 while((c = ll_iter_next(&it)))
77 uint8_t tmp_emmd5[MD5_DIGEST_LENGTH * 2 + 1];
78 char_to_hex(c->emmd5, MD5_DIGEST_LENGTH, tmp_emmd5);
79 uint8_t tmp_emm[c->len * 2 + 1];
80 char_to_hex(c->emm, c->len, tmp_emm);
82 result = fprintf(file, "%s,%ld,%ld,%02X,%04X,%s\n", tmp_emmd5, c->firstseen.time, c->lastseen.time, c->type, c->len, tmp_emm);
83 if(result < 0)
85 fclose(file);
86 result = remove(fname);
87 if(!result)
89 cs_log("error writing cache -> cache file removed!");
91 else
93 cs_log("error writing cache -> cache file could not be removed either!");
95 return;
97 count++;
100 fclose(file);
101 cs_ftime(&te);
102 int64_t load_time = comp_timeb(&te, &ts);
103 cs_log("saved %d emmcache records to %s in %"PRId64" ms", count, fname, load_time);
106 void load_emmstat_from_file(void)
108 if(boxtype_is("dbox2")) return; // dont load emmstat on these boxes, they lack resources and will crash!
110 if(!emm_cache_configured()){
111 cs_log("loading emmstats disabled since no reader is using it!");
112 return;
115 char buf[256];
116 char fname[256];
117 char *line;
118 FILE *file;
120 if(cfg.emmlogdir)
122 get_emmcache_filename(fname, sizeof(fname), "oscam.emmstat");
124 else
126 get_config_filename(fname, sizeof(fname), "oscam.emmstat");
129 file = fopen(fname, "r");
130 if(!file)
132 cs_log_dbg(D_TRACE, "can't read emmstats from file %s", fname);
133 return;
136 if(!cs_malloc(&line, LINESIZE))
138 fclose(file);
139 return;
142 struct timeb ts, te;
143 cs_ftime(&ts);
145 struct s_reader *rdr = NULL;
146 struct s_emmstat *s;
148 int32_t i = 1;
149 int32_t valid = 0;
150 int32_t count = 0;
151 char *ptr, *saveptr1 = NULL;
152 char *split[7];
154 while(fgets(line, LINESIZE, file))
156 if(!line[0] || line[0] == '#' || line[0] == ';')
157 { continue; }
159 if(!cs_malloc(&s, sizeof(struct s_emmstat)))
160 { continue; }
162 for(i = 0, ptr = strtok_r(line, ",", &saveptr1); ptr && i < 7 ; ptr = strtok_r(NULL, ",", &saveptr1), i++)
163 { split[i] = ptr; }
165 valid = (i == 6);
166 if(valid)
168 cs_strncpy(buf, split[0], sizeof(buf));
169 key_atob_l(split[1], s->emmd5, MD5_DIGEST_LENGTH * 2);
170 s->firstwritten.time = atol(split[2]);
171 s->lastwritten.time = atol(split[3]);
172 s->type = a2i(split[4], 2);
173 s->count = a2i(split[5], 4);
175 LL_ITER itr = ll_iter_create(configured_readers);
177 while((rdr = ll_iter_next(&itr)))
179 if(rdr->cachemm !=1) // skip: emmcache save is disabled
181 continue;
184 if(strcmp(rdr->label, buf) == 0)
186 break;
190 if(rdr != NULL)
192 if(!rdr->emmstat)
194 rdr->emmstat = ll_create("emmstat");
195 cs_lock_create(__func__, &rdr->emmstat_lock, rdr->label, DEFAULT_LOCK_TIMEOUT);
198 ll_append(rdr->emmstat, s);
199 count++;
201 else
203 cs_log("emmstats could not be loaded for %s", buf);
204 NULLFREE(s);
207 else
209 cs_log_dbg(D_EMM, "emmstat ERROR: %s count=%d type=%d", buf, s->count, s->type);
210 NULLFREE(s);
214 fclose(file);
215 NULLFREE(line);
217 cs_ftime(&te);
218 int64_t load_time = comp_timeb(&te, &ts);
219 cs_log("loaded %d emmstat records from %s in %"PRId64" ms", count, fname, load_time);
222 void save_emmstat_to_file(void)
224 if(boxtype_is("dbox2")) return; // don't save emmstat on these boxes, they lack resources and will crash!
226 if(!emm_cache_configured())
228 cs_log("saving emmstats disabled since no reader is using it!");
229 return;
232 char fname[256];
234 if(cfg.emmlogdir)
236 get_emmcache_filename(fname, sizeof(fname), "oscam.emmstat");
238 else
240 get_config_filename(fname, sizeof(fname), "oscam.emmstat");
242 FILE *file = fopen(fname, "w");
244 if(!file)
246 cs_log("can't write to file %s", fname);
247 return;
250 struct timeb ts, te;
251 cs_ftime(&ts);
253 int32_t count = 0, result = 0;
254 struct s_reader *rdr;
255 LL_ITER itr = ll_iter_create(configured_readers);
256 while((rdr = ll_iter_next(&itr)))
258 if(!rdr->cachemm || rdr->cachemm == 2)
260 cs_log("reader %s skipped since emmcache save is disabled", rdr->label);
261 continue;
264 if(rdr->emmstat)
266 cs_writelock(__func__, &rdr->emmstat_lock);
267 LL_ITER it = ll_iter_create(rdr->emmstat);
268 struct s_emmstat *s;
269 while((s = ll_iter_next(&it)))
271 uint8_t tmp_emmd5[MD5_DIGEST_LENGTH * 2 + 1];
272 char_to_hex(s->emmd5, MD5_DIGEST_LENGTH, tmp_emmd5);
273 result = fprintf(file, "%s,%s,%ld,%ld,%02X,%04X\n", rdr->label, tmp_emmd5, s->firstwritten.time, s->lastwritten.time, s->type, s->count);
274 if(result < 0)
276 cs_writeunlock(__func__, &rdr->emmstat_lock);
277 fclose(file);
278 result = remove(fname);
279 if(!result)
281 cs_log("error writing stats -> stat file removed!");
283 else
285 cs_log("error writing stats -> stat file could not be removed either!");
287 return;
289 count++;
291 cs_writeunlock(__func__, &rdr->emmstat_lock);
295 fclose(file);
297 cs_ftime(&te);
298 int64_t load_time = comp_timeb(&te, &ts);
300 cs_log("saved %d emmstat records to %s in %"PRId64" ms", count, fname, load_time);
303 void emm_load_cache(void)
305 if(boxtype_is("dbox2")) return; // don't load emmcache on these boxes, they lack resources and will crash!
307 if(!emm_cache_configured()){
308 cs_log("loading emmcache disabled since no reader is using it!");
309 return;
312 char fname[256];
313 char line[1024];
314 FILE *file;
315 struct s_emmcache *c;
317 if(cfg.emmlogdir)
319 get_emmcache_filename(fname, sizeof(fname), "oscam.emmcache");
321 else
323 get_config_filename(fname, sizeof(fname), "oscam.emmcache");
326 file = fopen(fname, "r");
327 if(!file)
329 cs_log_dbg(D_TRACE, "can't read emmcache from file %s", fname);
330 return;
333 struct timeb ts, te;
334 cs_ftime(&ts);
336 int32_t count = 0;
337 int32_t i = 1;
338 int32_t valid = 0;
339 char *ptr, *saveptr1 = NULL;
340 char *split[7];
342 memset(line, 0, sizeof(line));
343 while(fgets(line, sizeof(line), file))
345 if(!line[0] || line[0] == '#' || line[0] == ';')
346 { continue; }
348 for(i = 0, ptr = strtok_r(line, ",", &saveptr1); ptr && i < 7 ; ptr = strtok_r(NULL, ",", &saveptr1), i++)
350 split[i] = ptr;
353 valid = (i == 6);
354 if(valid)
356 if(!cs_malloc(&c, sizeof(struct s_emmcache)))
357 { continue; }
358 key_atob_l(split[0], c->emmd5, MD5_DIGEST_LENGTH*2);
359 c->firstseen.time = atol(split[1]);
360 c->lastseen.time = atol(split[2]);
361 c->type = a2i(split[3], 2);
362 c->len = a2i(split[4], 4);
363 key_atob_l(split[5], c->emm, c->len*2);
365 if(valid && c->len != 0)
367 if(!emm_cache)
369 emm_cache = ll_create("emm cache");
372 ll_append(emm_cache, c);
373 count++;
375 else
377 NULLFREE(c);
381 fclose(file);
382 cs_ftime(&te);
383 int64_t load_time = comp_timeb(&te, &ts);
384 cs_log("loaded %d emmcache records from %s in %"PRId64" ms", count, fname, load_time);
387 struct s_emmcache *find_emm_cache(uint8_t *emmd5)
389 struct s_emmcache *c;
390 LL_ITER it;
392 if(!emm_cache)
393 { emm_cache = ll_create("emm cache"); }
395 it = ll_iter_create(emm_cache);
396 while((c = ll_iter_next(&it)))
398 if(!memcmp(emmd5, c->emmd5, MD5_DIGEST_LENGTH))
400 cs_log_dump_dbg(D_EMM, c->emmd5, MD5_DIGEST_LENGTH, "found emmcache match");
401 return c;
404 return NULL;
407 int32_t clean_stale_emm_cache_and_stat(uint8_t *emmd5, int64_t gone)
409 struct timeb now;
410 cs_ftime(&now);
411 int32_t count = 0;
413 struct s_emmcache *c;
414 LL_ITER it;
416 if(!emm_cache)
417 { emm_cache = ll_create("emm cache"); }
419 it = ll_iter_create(emm_cache);
420 while((c = ll_iter_next(&it)))
422 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!
424 struct s_reader *rdr;
425 LL_ITER rdr_itr = ll_iter_create(configured_readers);
426 while((rdr = ll_iter_next(&rdr_itr)))
428 if(rdr->emmstat && !(caid_is_irdeto(rdr->caid) || caid_is_videoguard(rdr->caid)))
430 remove_emm_stat(rdr, c->emmd5); // clean stale entry from stats
431 count++;
434 ll_iter_remove_data(&it); // clean stale entry from emmcache
437 return count;
440 int32_t emm_edit_cache(uint8_t *emmd5, EMM_PACKET *ep, bool add)
442 struct s_emmcache *c;
443 LL_ITER it;
444 int32_t count = 0;
446 if(!emm_cache)
447 { emm_cache = ll_create("emm cache"); }
449 it = ll_iter_create(emm_cache);
450 while((c = ll_iter_next(&it)))
452 if(!memcmp(emmd5, c->emmd5, MD5_DIGEST_LENGTH))
454 if(add)
456 return 0; // already added
458 ll_iter_remove_data(&it);
459 count++;
463 if(add)
465 if(!cs_malloc(&c, sizeof(struct s_emmcache)))
466 { return count; }
467 memcpy(c->emmd5, emmd5, MD5_DIGEST_LENGTH);
468 c->type = ep->type;
469 c->len = SCT_LEN(ep->emm);
470 cs_ftime(&c->firstseen);
471 c->lastseen = c->firstseen;
472 memcpy(c->emm, ep->emm, c->len);
473 ll_append(emm_cache, c);
474 #ifdef WITH_DEBUG
475 cs_log_dump_dbg(D_EMM, c->emmd5, MD5_DIGEST_LENGTH, "added emm to cache:");
476 #endif
477 count++;
480 return count;
483 int32_t remove_emm_stat(struct s_reader *rdr, uint8_t *emmd5)
485 int32_t count = 0;
486 if(rdr && rdr->emmstat)
488 cs_writelock(__func__, &rdr->emmstat_lock);
489 struct s_emmstat *c;
490 LL_ITER itr = ll_iter_create(rdr->emmstat);
491 while((c = ll_iter_next(&itr)))
493 if(!memcmp(emmd5, c->emmd5, MD5_DIGEST_LENGTH))
495 ll_iter_remove_data(&itr);
496 count++;
497 break;
501 cs_writeunlock(__func__, &rdr->emmstat_lock);
503 return count;
506 struct s_emmstat *get_emm_stat(struct s_reader *rdr, uint8_t *emmd5, uint8_t emmtype)
508 if(!rdr->cachemm) return NULL;
510 struct s_emmstat *c;
511 LL_ITER it;
513 if(!rdr->emmstat)
514 { rdr->emmstat = ll_create("emm stat"); }
516 it = ll_iter_create(rdr->emmstat);
517 while((c = ll_iter_next(&it)))
519 if(!memcmp(emmd5, c->emmd5, MD5_DIGEST_LENGTH))
521 cs_log_dump_dbg(D_EMM, c->emmd5, MD5_DIGEST_LENGTH, "found emmstat match (reader:%s, count:%d)", rdr->label, c->count);
522 return c;
526 if(cs_malloc(&c, sizeof(struct s_emmstat)))
528 memcpy(c->emmd5, emmd5, MD5_DIGEST_LENGTH);
529 c->type = emmtype;
530 ll_append(rdr->emmstat, c);
531 cs_log_dump_dbg(D_EMM, c->emmd5, MD5_DIGEST_LENGTH, "added emmstat (reader:%s, count:%d)", rdr->label, c->count);
533 return c;