- fix for ticker #4787
[oscam.git] / oscam-emm-cache.c
blob33c08687fb8066ee1a19572df93315caf571be0f
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 void emm_save_cache(void)
33 if(boxtype_is("dbox2")) return; // don't save emmcache on these boxes, they lack resources and will crash!
35 if(!emm_cache_configured()){
36 cs_log("saving emmcache disabled since no reader is using it!");
37 return;
40 char fname[256];
41 struct timeb ts, te;
43 if(!cfg.emmlogdir)
45 get_tmp_dir_filename(fname, sizeof(fname), "oscam.emmcache");
47 else
49 get_config_filename(fname, sizeof(fname), "oscam.emmcache");
51 FILE *file = fopen(fname, "w");
53 if(!file)
55 cs_log("can't write emmcache to file %s", fname);
56 return;
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;
64 while((c = ll_iter_next(&it)))
66 uint8_t tmp_emmd5[MD5_DIGEST_LENGTH * 2 + 1];
67 char_to_hex(c->emmd5, MD5_DIGEST_LENGTH, tmp_emmd5);
68 uint8_t tmp_emm[c->len * 2 + 1];
69 char_to_hex(c->emm, c->len, tmp_emm);
71 result = fprintf(file, "%s,%ld,%ld,%02X,%04X,%s\n", tmp_emmd5, c->firstseen.time, c->lastseen.time, c->type, c->len, tmp_emm);
72 if(result < 0)
74 fclose(file);
75 result = remove(fname);
76 if(!result)
78 cs_log("error writing cache -> cache file removed!");
80 else
82 cs_log("error writing cache -> cache file could not be removed either!");
84 return;
86 count++;
89 fclose(file);
90 cs_ftime(&te);
91 int64_t load_time = comp_timeb(&te, &ts);
92 cs_log("saved %d emmcache records to %s in %"PRId64" ms", count, fname, load_time);
95 void load_emmstat_from_file(void)
97 if(boxtype_is("dbox2")) return; // dont load emmstat on these boxes, they lack resources and will crash!
99 if(!emm_cache_configured()){
100 cs_log("loading emmstats disabled since no reader is using it!");
101 return;
104 char buf[256];
105 char fname[256];
106 char *line;
107 FILE *file;
109 if(!cfg.emmlogdir)
111 get_tmp_dir_filename(fname, sizeof(fname), "oscam.emmstat");
113 else
115 get_config_filename(fname, sizeof(fname), "oscam.emmstat");
118 file = fopen(fname, "r");
119 if(!file)
121 cs_log_dbg(D_TRACE, "can't read emmstats from file %s", fname);
122 return;
125 if(!cs_malloc(&line, LINESIZE))
127 fclose(file);
128 return;
131 struct timeb ts, te;
132 cs_ftime(&ts);
134 struct s_reader *rdr = NULL;
135 struct s_emmstat *s;
137 int32_t i = 1;
138 int32_t valid = 0;
139 int32_t count = 0;
140 char *ptr, *saveptr1 = NULL;
141 char *split[7];
143 while(fgets(line, LINESIZE, file))
145 if(!line[0] || line[0] == '#' || line[0] == ';')
146 { continue; }
148 if(!cs_malloc(&s, sizeof(struct s_emmstat)))
149 { continue; }
151 for(i = 0, ptr = strtok_r(line, ",", &saveptr1); ptr && i < 7 ; ptr = strtok_r(NULL, ",", &saveptr1), i++)
152 { split[i] = ptr; }
154 valid = (i == 6);
155 if(valid)
157 cs_strncpy(buf, split[0], sizeof(buf));
158 key_atob_l(split[1], s->emmd5, MD5_DIGEST_LENGTH * 2);
159 s->firstwritten.time = atol(split[2]);
160 s->lastwritten.time = atol(split[3]);
161 s->type = a2i(split[4], 2);
162 s->count = a2i(split[5], 4);
164 LL_ITER itr = ll_iter_create(configured_readers);
166 while((rdr = ll_iter_next(&itr)))
168 if(rdr->cachemm !=1) // skip: emmcache save is disabled
170 continue;
173 if(strcmp(rdr->label, buf) == 0)
175 break;
179 if(rdr != NULL)
181 if(!rdr->emmstat)
183 rdr->emmstat = ll_create("emmstat");
184 cs_lock_create(__func__, &rdr->emmstat_lock, rdr->label, DEFAULT_LOCK_TIMEOUT);
187 ll_append(rdr->emmstat, s);
188 count++;
190 else
192 cs_log("emmstats could not be loaded for %s", buf);
193 NULLFREE(s);
196 else
198 cs_log_dbg(D_EMM, "emmstat ERROR: %s count=%d type=%d", buf, s->count, s->type);
199 NULLFREE(s);
203 fclose(file);
204 NULLFREE(line);
206 cs_ftime(&te);
207 int64_t load_time = comp_timeb(&te, &ts);
208 cs_log("loaded %d emmstat records from %s in %"PRId64" ms", count, fname, load_time);
211 void save_emmstat_to_file(void)
213 if(boxtype_is("dbox2")) return; // don't save emmstat on these boxes, they lack resources and will crash!
215 if(!emm_cache_configured())
217 cs_log("saving emmstats disabled since no reader is using it!");
218 return;
221 char fname[256];
223 if(!cfg.emmlogdir)
225 get_tmp_dir_filename(fname, sizeof(fname), "oscam.emmstat");
227 else
229 get_config_filename(fname, sizeof(fname), "oscam.emmstat");
231 FILE *file = fopen(fname, "w");
233 if(!file)
235 cs_log("can't write to file %s", fname);
236 return;
239 struct timeb ts, te;
240 cs_ftime(&ts);
242 int32_t count = 0, result = 0;
243 struct s_reader *rdr;
244 LL_ITER itr = ll_iter_create(configured_readers);
245 while((rdr = ll_iter_next(&itr)))
247 if(!rdr->cachemm || rdr->cachemm == 2)
249 cs_log("reader %s skipped since emmcache save is disabled", rdr->label);
250 continue;
253 if(rdr->emmstat)
255 cs_writelock(__func__, &rdr->emmstat_lock);
256 LL_ITER it = ll_iter_create(rdr->emmstat);
257 struct s_emmstat *s;
258 while((s = ll_iter_next(&it)))
260 uint8_t tmp_emmd5[MD5_DIGEST_LENGTH * 2 + 1];
261 char_to_hex(s->emmd5, MD5_DIGEST_LENGTH, tmp_emmd5);
262 result = fprintf(file, "%s,%s,%ld,%ld,%02X,%04X\n", rdr->label, tmp_emmd5, s->firstwritten.time, s->lastwritten.time, s->type, s->count);
263 if(result < 0)
265 cs_writeunlock(__func__, &rdr->emmstat_lock);
266 fclose(file);
267 result = remove(fname);
268 if(!result)
270 cs_log("error writing stats -> stat file removed!");
272 else
274 cs_log("error writing stats -> stat file could not be removed either!");
276 return;
278 count++;
280 cs_writeunlock(__func__, &rdr->emmstat_lock);
284 fclose(file);
286 cs_ftime(&te);
287 int64_t load_time = comp_timeb(&te, &ts);
289 cs_log("saved %d emmstat records to %s in %"PRId64" ms", count, fname, load_time);
292 void emm_load_cache(void)
294 if(boxtype_is("dbox2")) return; // don't load emmcache on these boxes, they lack resources and will crash!
296 if(!emm_cache_configured()){
297 cs_log("loading emmcache disabled since no reader is using it!");
298 return;
301 char fname[256];
302 char line[1024];
303 FILE *file;
304 struct s_emmcache *c;
306 if(!cfg.emmlogdir)
308 get_tmp_dir_filename(fname, sizeof(fname), "oscam.emmcache");
310 else
312 get_config_filename(fname, sizeof(fname), "oscam.emmcache");
315 file = fopen(fname, "r");
316 if(!file)
318 cs_log_dbg(D_TRACE, "can't read emmcache from file %s", fname);
319 return;
322 struct timeb ts, te;
323 cs_ftime(&ts);
325 int32_t count = 0;
326 int32_t i = 1;
327 int32_t valid = 0;
328 char *ptr, *saveptr1 = NULL;
329 char *split[7];
331 memset(line, 0, sizeof(line));
332 while(fgets(line, sizeof(line), file))
334 if(!line[0] || line[0] == '#' || line[0] == ';')
335 { continue; }
337 for(i = 0, ptr = strtok_r(line, ",", &saveptr1); ptr && i < 7 ; ptr = strtok_r(NULL, ",", &saveptr1), i++)
339 split[i] = ptr;
342 valid = (i == 6);
343 if(valid)
345 if(!cs_malloc(&c, sizeof(struct s_emmcache)))
346 { continue; }
347 key_atob_l(split[0], c->emmd5, MD5_DIGEST_LENGTH*2);
348 c->firstseen.time = atol(split[1]);
349 c->lastseen.time = atol(split[2]);
350 c->type = a2i(split[3], 2);
351 c->len = a2i(split[4], 4);
352 key_atob_l(split[5], c->emm, c->len*2);
354 if(valid && c->len != 0)
356 if(!emm_cache)
358 emm_cache = ll_create("emm cache");
361 ll_append(emm_cache, c);
362 count++;
364 else
366 NULLFREE(c);
370 fclose(file);
371 cs_ftime(&te);
372 int64_t load_time = comp_timeb(&te, &ts);
373 cs_log("loaded %d emmcache records from %s in %"PRId64" ms", count, fname, load_time);
376 struct s_emmcache *find_emm_cache(uint8_t *emmd5)
378 struct s_emmcache *c;
379 LL_ITER it;
381 if(!emm_cache)
382 { emm_cache = ll_create("emm cache"); }
384 it = ll_iter_create(emm_cache);
385 while((c = ll_iter_next(&it)))
387 if(!memcmp(emmd5, c->emmd5, MD5_DIGEST_LENGTH))
389 cs_log_dump_dbg(D_EMM, c->emmd5, MD5_DIGEST_LENGTH, "found emmcache match");
390 return c;
393 return NULL;
396 int32_t clean_stale_emm_cache_and_stat(uint8_t *emmd5, int64_t gone)
398 struct timeb now;
399 cs_ftime(&now);
400 int32_t count = 0;
402 struct s_emmcache *c;
403 LL_ITER it;
405 if(!emm_cache)
406 { emm_cache = ll_create("emm cache"); }
408 it = ll_iter_create(emm_cache);
409 while((c = ll_iter_next(&it)))
411 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!
413 struct s_reader *rdr;
414 LL_ITER rdr_itr = ll_iter_create(configured_readers);
415 while((rdr = ll_iter_next(&rdr_itr)))
417 if(rdr->emmstat && !(caid_is_irdeto(rdr->caid) || caid_is_videoguard(rdr->caid)))
419 remove_emm_stat(rdr, c->emmd5); // clean stale entry from stats
420 count++;
423 ll_iter_remove_data(&it); // clean stale entry from emmcache
426 return count;
429 int32_t emm_edit_cache(uint8_t *emmd5, EMM_PACKET *ep, bool add)
431 struct s_emmcache *c;
432 LL_ITER it;
433 int32_t count = 0;
435 if(!emm_cache)
436 { emm_cache = ll_create("emm cache"); }
438 it = ll_iter_create(emm_cache);
439 while((c = ll_iter_next(&it)))
441 if(!memcmp(emmd5, c->emmd5, MD5_DIGEST_LENGTH))
443 if(add)
445 return 0; // already added
447 ll_iter_remove_data(&it);
448 count++;
452 if(add)
454 if(!cs_malloc(&c, sizeof(struct s_emmcache)))
455 { return count; }
456 memcpy(c->emmd5, emmd5, MD5_DIGEST_LENGTH);
457 c->type = ep->type;
458 c->len = SCT_LEN(ep->emm);
459 cs_ftime(&c->firstseen);
460 c->lastseen = c->firstseen;
461 memcpy(c->emm, ep->emm, c->len);
462 ll_append(emm_cache, c);
463 #ifdef WITH_DEBUG
464 cs_log_dump_dbg(D_EMM, c->emmd5, MD5_DIGEST_LENGTH, "added emm to cache:");
465 #endif
466 count++;
469 return count;
472 int32_t remove_emm_stat(struct s_reader *rdr, uint8_t *emmd5)
474 int32_t count = 0;
475 if(rdr && rdr->emmstat)
477 cs_writelock(__func__, &rdr->emmstat_lock);
478 struct s_emmstat *c;
479 LL_ITER itr = ll_iter_create(rdr->emmstat);
480 while((c = ll_iter_next(&itr)))
482 if(!memcmp(emmd5, c->emmd5, MD5_DIGEST_LENGTH))
484 ll_iter_remove_data(&itr);
485 count++;
486 break;
490 cs_writeunlock(__func__, &rdr->emmstat_lock);
492 return count;
495 struct s_emmstat *get_emm_stat(struct s_reader *rdr, uint8_t *emmd5, uint8_t emmtype)
497 if(!rdr->cachemm) return NULL;
499 struct s_emmstat *c;
500 LL_ITER it;
502 if(!rdr->emmstat)
503 { rdr->emmstat = ll_create("emm stat"); }
505 it = ll_iter_create(rdr->emmstat);
506 while((c = ll_iter_next(&it)))
508 if(!memcmp(emmd5, c->emmd5, MD5_DIGEST_LENGTH))
510 cs_log_dump_dbg(D_EMM, c->emmd5, MD5_DIGEST_LENGTH, "found emmstat match (reader:%s, count:%d)", rdr->label, c->count);
511 return c;
515 if(cs_malloc(&c, sizeof(struct s_emmstat)))
517 memcpy(c->emmd5, emmd5, MD5_DIGEST_LENGTH);
518 c->type = emmtype;
519 ll_append(rdr->emmstat, c);
520 cs_log_dump_dbg(D_EMM, c->emmd5, MD5_DIGEST_LENGTH, "added emmstat (reader:%s, count:%d)", rdr->label, c->count);
522 return c;