1 /*
2 * Electronic Program Guide - EPG grabber OTA functions
3 * Copyright (C) 2012 Adam Sutton
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include "tvheadend.h"
20 #include "queue.h"
21 #include "settings.h"
22 #include "epg.h"
23 #include "epggrab.h"
24 #include "epggrab/private.h"
25 #include "input.h"
26 #include "subscriptions.h"
27 #include "cron.h"
28 #include "dbus.h"
29
30 #include <string.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <unistd.h>
34
35 #define EPGGRAB_OTA_MIN_TIMEOUT 30
36 #define EPGGRAB_OTA_MAX_TIMEOUT 7200
37
38 #define EPGGRAB_OTA_DONE_COMPLETE 0
39 #define EPGGRAB_OTA_DONE_TIMEOUT 1
40 #define EPGGRAB_OTA_DONE_NO_DATA 2
41 #define EPGGRAB_OTA_DONE_STOLEN 3
42
43 typedef TAILQ_HEAD(epggrab_ota_head,epggrab_ota_mux) epggrab_ota_head_t;
44
45 cron_multi_t *epggrab_ota_cron_multi;
46
47 RB_HEAD(,epggrab_ota_mux) epggrab_ota_all;
48 epggrab_ota_head_t epggrab_ota_pending;
49 epggrab_ota_head_t epggrab_ota_active;
50
51 mtimer_t epggrab_ota_kick_timer;
52 gtimer_t epggrab_ota_start_timer;
53
54 int epggrab_ota_running;
55 int epggrab_ota_pending_flag;
56
57 pthread_mutex_t epggrab_ota_mutex;
58
59 SKEL_DECLARE(epggrab_ota_mux_skel, epggrab_ota_mux_t);
60 SKEL_DECLARE(epggrab_svc_link_skel, epggrab_ota_svc_link_t);
61
62 static void epggrab_ota_kick ( int delay );
63
64 static void epggrab_ota_timeout_cb ( void *p );
65 static void epggrab_ota_data_timeout_cb ( void *p );
66 static void epggrab_ota_kick_cb ( void *p );
67
68 static void epggrab_mux_start ( mpegts_mux_t *mm, void *p );
69
70 static void epggrab_ota_save ( epggrab_ota_mux_t *ota );
71
72 static void epggrab_ota_free ( epggrab_ota_head_t *head, epggrab_ota_mux_t *ota );
73
74 /* **************************************************************************
75 * Utilities
76 * *************************************************************************/
77
78 static int
om_id_cmp(epggrab_ota_mux_t * a,epggrab_ota_mux_t * b)79 om_id_cmp ( epggrab_ota_mux_t *a, epggrab_ota_mux_t *b )
80 {
81 return strcmp(a->om_mux_uuid, b->om_mux_uuid);
82 }
83
84 static int
om_mux_cmp(epggrab_ota_mux_t * a,epggrab_ota_mux_t * b)85 om_mux_cmp ( epggrab_ota_mux_t *a, epggrab_ota_mux_t *b )
86 {
87 mpegts_mux_t *a1 = mpegts_mux_find(a->om_mux_uuid);
88 mpegts_mux_t *b1 = mpegts_mux_find(b->om_mux_uuid);
89 if (a1 == NULL || b1 == NULL) {
90 if (a1 == NULL && b1 == NULL)
91 return 0;
92 return a1 == NULL ? 1 : -1;
93 }
94 return mpegts_mux_compare(a1, b1);
95 }
96
97 static int
om_svcl_cmp(epggrab_ota_svc_link_t * a,epggrab_ota_svc_link_t * b)98 om_svcl_cmp ( epggrab_ota_svc_link_t *a, epggrab_ota_svc_link_t *b )
99 {
100 return strcmp(a->uuid, b->uuid);
101 }
102
103 static int
epggrab_ota_timeout_get(void)104 epggrab_ota_timeout_get ( void )
105 {
106 int timeout = epggrab_conf.ota_timeout;
107
108 if (timeout < EPGGRAB_OTA_MIN_TIMEOUT)
109 timeout = EPGGRAB_OTA_MIN_TIMEOUT;
110 if (timeout > EPGGRAB_OTA_MAX_TIMEOUT)
111 timeout = EPGGRAB_OTA_MAX_TIMEOUT;
112
113 return timeout;
114 }
115
116 static int
epggrab_ota_queue_one(epggrab_ota_mux_t * om)117 epggrab_ota_queue_one( epggrab_ota_mux_t *om )
118 {
119 om->om_done = 0;
120 om->om_requeue = 1;
121 if (om->om_q_type != EPGGRAB_OTA_MUX_IDLE)
122 return 0;
123 TAILQ_INSERT_SORTED(&epggrab_ota_pending, om, om_q_link, om_mux_cmp);
124 om->om_q_type = EPGGRAB_OTA_MUX_PENDING;
125 return 1;
126 }
127
128 void
epggrab_ota_queue_mux(mpegts_mux_t * mm)129 epggrab_ota_queue_mux( mpegts_mux_t *mm )
130 {
131 const char *id;
132 epggrab_ota_mux_t *om;
133 int epg_flag;
134 char ubuf[UUID_HEX_SIZE];
135
136 if (!mm)
137 return;
138
139 lock_assert(&global_lock);
140
141 id = idnode_uuid_as_str(&mm->mm_id, ubuf);
142 epg_flag = mm->mm_is_epg(mm);
143 if (epg_flag < 0 || epg_flag == MM_EPG_DISABLE)
144 return;
145 RB_FOREACH(om, &epggrab_ota_all, om_global_link)
146 if (!strcmp(om->om_mux_uuid, id)) {
147 if (epggrab_ota_queue_one(om))
148 epggrab_ota_kick(4);
149 break;
150 }
151 }
152
153 static void
epggrab_ota_requeue(void)154 epggrab_ota_requeue ( void )
155 {
156 epggrab_ota_mux_t *om;
157
158 /*
159 * enqueue all muxes, but ommit the delayed ones (active+pending)
160 */
161 RB_FOREACH(om, &epggrab_ota_all, om_global_link)
162 epggrab_ota_queue_one(om);
163 }
164
165 static void
epggrab_ota_kick(int delay)166 epggrab_ota_kick ( int delay )
167 {
168 /* next round is pending? queue rest of ota muxes */
169 if (epggrab_ota_pending_flag) {
170 epggrab_ota_pending_flag = 0;
171 epggrab_ota_requeue();
172 }
173
174 if (TAILQ_EMPTY(&epggrab_ota_pending))
175 return;
176
177 mtimer_arm_rel(&epggrab_ota_kick_timer, epggrab_ota_kick_cb, NULL, sec2mono(delay));
178 }
179
180 static void
epggrab_ota_done(epggrab_ota_mux_t * om,int reason)181 epggrab_ota_done ( epggrab_ota_mux_t *om, int reason )
182 {
183 static const char *reasons[] = {
184 [EPGGRAB_OTA_DONE_COMPLETE] = "complete",
185 [EPGGRAB_OTA_DONE_TIMEOUT] = "timeout",
186 [EPGGRAB_OTA_DONE_NO_DATA] = "no data",
187 [EPGGRAB_OTA_DONE_STOLEN] = "stolen"
188 };
189 char name[256];
190 mpegts_mux_t *mm;
191 epggrab_ota_map_t *map;
192
193 if (om->om_save)
194 epggrab_ota_save(om);
195
196 mm = mpegts_mux_find(om->om_mux_uuid);
197 mpegts_mux_nice_name(mm, name, sizeof(name));
198 tvhdebug(LS_EPGGRAB, "grab done for %s (%s)", name, reasons[reason]);
199
200 mtimer_disarm(&om->om_timer);
201 mtimer_disarm(&om->om_data_timer);
202
203 assert(om->om_q_type == EPGGRAB_OTA_MUX_ACTIVE);
204 TAILQ_REMOVE(&epggrab_ota_active, om, om_q_link);
205 om->om_q_type = EPGGRAB_OTA_MUX_IDLE;
206 if (reason == EPGGRAB_OTA_DONE_STOLEN) {
207 /* Do not requeue completed muxes */
208 if (!om->om_done && om->om_requeue) {
209 TAILQ_INSERT_HEAD(&epggrab_ota_pending, om, om_q_link);
210 om->om_q_type = EPGGRAB_OTA_MUX_PENDING;
211 } else {
212 om->om_requeue = 0;
213 }
214 } else if (reason == EPGGRAB_OTA_DONE_TIMEOUT) {
215 om->om_requeue = 0;
216 LIST_FOREACH(map, &om->om_modules, om_link)
217 if (!map->om_complete)
218 tvhwarn(LS_EPGGRAB, "%s - data completion timeout for %s", map->om_module->name, name);
219 } else {
220 om->om_requeue = 0;
221 }
222
223 /* Remove subscriber */
224 if (mm)
225 mpegts_mux_unsubscribe_by_name(mm, "epggrab");
226
227 /* Kick - try start waiting muxes */
228 epggrab_ota_kick(1);
229 }
230
231 static void
epggrab_ota_complete_mark(epggrab_ota_mux_t * om,int done)232 epggrab_ota_complete_mark ( epggrab_ota_mux_t *om, int done )
233 {
234 om->om_done = 1;
235 if (!om->om_complete) {
236 om->om_complete = 1;
237 epggrab_ota_save(om);
238 }
239 }
240
241 static void
epggrab_ota_start(epggrab_ota_mux_t * om,mpegts_mux_t * mm)242 epggrab_ota_start ( epggrab_ota_mux_t *om, mpegts_mux_t *mm )
243 {
244 epggrab_module_t *m;
245 epggrab_ota_map_t *map;
246 char *modname = om->om_force_modname;
247 mpegts_mux_instance_t *mmi = mm->mm_active;
248 int grace;
249
250 /* In pending queue? Remove.. */
251 if (om->om_q_type == EPGGRAB_OTA_MUX_PENDING)
252 TAILQ_REMOVE(&epggrab_ota_pending, om, om_q_link);
253 else
254 assert(om->om_q_type == EPGGRAB_OTA_MUX_IDLE);
255
256 TAILQ_INSERT_TAIL(&epggrab_ota_active, om, om_q_link);
257 om->om_q_type = EPGGRAB_OTA_MUX_ACTIVE;
258 grace = mpegts_input_grace(mmi->mmi_input, mm);
259 mtimer_arm_rel(&om->om_timer, epggrab_ota_timeout_cb, om,
260 sec2mono(epggrab_ota_timeout_get() + grace));
261 mtimer_arm_rel(&om->om_data_timer, epggrab_ota_data_timeout_cb, om,
262 sec2mono(30 + grace)); /* 30 seconds to receive any EPG info */
263 if (modname) {
264 LIST_FOREACH(m, &epggrab_modules, link)
265 if (!strcmp(m->id, modname)) {
266 epggrab_ota_register((epggrab_module_ota_t *)m, om, mm);
267 break;
268 }
269 }
270 LIST_FOREACH(map, &om->om_modules, om_link) {
271 map->om_first = 1;
272 map->om_forced = 0;
273 if (modname && !strcmp(modname, map->om_module->id))
274 map->om_forced = 1;
275 map->om_complete = 0;
276 if (map->om_module->start(map, mm) < 0) {
277 map->om_complete = 1;
278 } else
279 tvhdebug(map->om_module->subsys, "%s: grab started", map->om_module->id);
280 }
281 }
282
283 /* **************************************************************************
284 * MPEG-TS listener
285 * *************************************************************************/
286
287 static void
epggrab_mux_start(mpegts_mux_t * mm,void * p)288 epggrab_mux_start ( mpegts_mux_t *mm, void *p )
289 {
290 epggrab_module_t *m;
291 epggrab_ota_mux_t *ota;
292 char ubuf[UUID_HEX_SIZE];
293 const char *uuid = idnode_uuid_as_str(&mm->mm_id, ubuf);
294
295 /* Already started */
296 TAILQ_FOREACH(ota, &epggrab_ota_active, om_q_link)
297 if (!strcmp(ota->om_mux_uuid, uuid))
298 return;
299
300 /* Register all modules */
301 ota = NULL;
302 LIST_FOREACH(m, &epggrab_modules, link) {
303 if (m->type == EPGGRAB_OTA && m->enabled)
304 ota = epggrab_ota_register((epggrab_module_ota_t *)m, ota, mm);
305 }
306
307 if (ota)
308 epggrab_ota_start(ota, mm);
309 }
310
311 static void
epggrab_mux_stop(mpegts_mux_t * mm,void * p,int reason)312 epggrab_mux_stop ( mpegts_mux_t *mm, void *p, int reason )
313 {
314 epggrab_ota_mux_t *ota;
315 char ubuf[UUID_HEX_SIZE], name[256];
316 const char *uuid = idnode_uuid_as_str(&mm->mm_id, ubuf);
317 int done = EPGGRAB_OTA_DONE_STOLEN;
318
319 if (reason == SM_CODE_NO_INPUT)
320 done = EPGGRAB_OTA_DONE_NO_DATA;
321
322 if (tvhtrace_enabled()) {
323 mpegts_mux_nice_name(mm, name, sizeof(name));
324 tvhtrace(LS_EPGGRAB, "mux %s (%p) stop", name, mm);
325 }
326 TAILQ_FOREACH(ota, &epggrab_ota_active, om_q_link)
327 if (!strcmp(ota->om_mux_uuid, uuid)) {
328 epggrab_ota_done(ota, done);
329 break;
330 }
331 }
332
333 /* **************************************************************************
334 * Module methods
335 * *************************************************************************/
336
337 epggrab_ota_mux_t *
epggrab_ota_register(epggrab_module_ota_t * mod,epggrab_ota_mux_t * ota,mpegts_mux_t * mm)338 epggrab_ota_register
339 ( epggrab_module_ota_t *mod, epggrab_ota_mux_t *ota, mpegts_mux_t *mm )
340 {
341 int save = 0;
342 epggrab_ota_map_t *map;
343
344 if (!atomic_get(&epggrab_ota_running))
345 return NULL;
346
347 if (ota == NULL) {
348 /* Find mux entry */
349 char ubuf[UUID_HEX_SIZE];
350 const char *uuid = idnode_uuid_as_str(&mm->mm_id, ubuf);
351 SKEL_ALLOC(epggrab_ota_mux_skel);
352 epggrab_ota_mux_skel->om_mux_uuid = (char*)uuid;
353
354 ota = RB_INSERT_SORTED(&epggrab_ota_all, epggrab_ota_mux_skel, om_global_link, om_id_cmp);
355 if (!ota) {
356 char buf[256];
357 mpegts_mux_nice_name(mm, buf, sizeof(buf));
358 tvhinfo(LS_EPGGRAB, "%s - registering mux for OTA EPG", buf);
359 ota = epggrab_ota_mux_skel;
360 SKEL_USED(epggrab_ota_mux_skel);
361 ota->om_mux_uuid = strdup(uuid);
362 TAILQ_INSERT_SORTED(&epggrab_ota_pending, ota, om_q_link, om_mux_cmp);
363 ota->om_q_type = EPGGRAB_OTA_MUX_PENDING;
364 if (TAILQ_FIRST(&epggrab_ota_pending) == ota)
365 epggrab_ota_kick(1);
366 save = 1;
367 }
368 }
369
370 /* Find module entry */
371 LIST_FOREACH(map, &ota->om_modules, om_link)
372 if (map->om_module == mod)
373 break;
374 if (!map) {
375 map = calloc(1, sizeof(epggrab_ota_map_t));
376 RB_INIT(&map->om_svcs);
377 map->om_module = mod;
378 LIST_INSERT_HEAD(&ota->om_modules, map, om_link);
379 save = 1;
380 }
381
382 /* Save config */
383 if (save) epggrab_ota_save(ota);
384
385 return ota;
386 }
387
388 void
epggrab_ota_complete(epggrab_module_ota_t * mod,epggrab_ota_mux_t * ota)389 epggrab_ota_complete
390 ( epggrab_module_ota_t *mod, epggrab_ota_mux_t *ota )
391 {
392 int done = 1;
393 epggrab_ota_map_t *map;
394 lock_assert(&global_lock);
395
396 if (!ota->om_complete)
397 tvhdebug(mod->subsys, "%s: grab complete", mod->id);
398
399 /* Test for completion */
400 LIST_FOREACH(map, &ota->om_modules, om_link) {
401 if (map->om_module == mod) {
402 map->om_complete = 1;
403 } else if (!map->om_complete && !map->om_first) {
404 done = 0;
405 }
406 tvhtrace(LS_EPGGRAB, "%s complete %i first %i",
407 map->om_module->id, map->om_complete, map->om_first);
408 }
409
410 epggrab_ota_complete_mark(ota, done);
411
412 if (!done) return;
413
414 /* Done */
415 if (ota->om_q_type == EPGGRAB_OTA_MUX_ACTIVE)
416 epggrab_ota_done(ota, EPGGRAB_OTA_DONE_COMPLETE);
417 else if (ota->om_q_type == EPGGRAB_OTA_MUX_PENDING) {
418 TAILQ_REMOVE(&epggrab_ota_pending, ota, om_q_link);
419 ota->om_q_type = EPGGRAB_OTA_MUX_IDLE;
420 }
421 }
422
423 /* **************************************************************************
424 * Timer callbacks
425 * *************************************************************************/
426
427 static void
epggrab_ota_timeout_cb(void * p)428 epggrab_ota_timeout_cb ( void *p )
429 {
430 epggrab_ota_mux_t *om = p;
431
432 lock_assert(&global_lock);
433
434 if (!om)
435 return;
436
437 /* Abort */
438 epggrab_ota_done(om, EPGGRAB_OTA_DONE_TIMEOUT);
439 /* Not completed, but no further data for a long period */
440 /* wait for a manual mux tuning */
441 epggrab_ota_complete_mark(om, 1);
442 }
443
444 static void
epggrab_ota_data_timeout_cb(void * p)445 epggrab_ota_data_timeout_cb ( void *p )
446 {
447 epggrab_ota_mux_t *om = p;
448 epggrab_ota_map_t *map;
449
450 lock_assert(&global_lock);
451
452 if (!om)
453 return;
454
455 /* Test for any valid data reception */
456 LIST_FOREACH(map, &om->om_modules, om_link) {
457 if (!map->om_first)
458 break;
459 }
460
461 if (map == NULL) {
462 /* Abort */
463 epggrab_ota_done(om, EPGGRAB_OTA_DONE_NO_DATA);
464 /* Not completed, but no data - wait for a manual mux tuning */
465 epggrab_ota_complete_mark(om, 1);
466 } else {
467 tvhtrace(LS_EPGGRAB, "data timeout check succeed");
468 }
469 }
470
471 static void
epggrab_ota_kick_cb(void * p)472 epggrab_ota_kick_cb ( void *p )
473 {
474 extern const idclass_t mpegts_mux_class;
475 epggrab_ota_map_t *map;
476 epggrab_ota_mux_t *om = TAILQ_FIRST(&epggrab_ota_pending);
477 mpegts_mux_t *mm;
478 char name[256];
479 struct {
480 mpegts_network_t *net;
481 uint8_t failed;
482 uint8_t fatal;
483 } networks[64], *net; /* more than 64 networks? - you're a king */
484 int i, r, networks_count = 0, epg_flag, kick = 1;
485 const char *modname;
486 static const char *modnames[] = {
487 [MM_EPG_DISABLE] = NULL,
488 [MM_EPG_ENABLE] = NULL,
489 [MM_EPG_FORCE] = NULL,
490 [MM_EPG_ONLY_EIT] = "eit",
491 [MM_EPG_ONLY_PSIP] = "psip",
492 [MM_EPG_ONLY_UK_FREESAT] = "uk_freesat",
493 [MM_EPG_ONLY_UK_FREEVIEW] = "uk_freeview",
494 [MM_EPG_ONLY_VIASAT_BALTIC] = "viasat_baltic",
495 [MM_EPG_ONLY_BULSATCOM_39E] = "Bulsatcom_39E",
496 [MM_EPG_ONLY_OPENTV_SKY_UK] = "opentv-skyuk",
497 [MM_EPG_ONLY_OPENTV_SKY_ITALIA] = "opentv-skyit",
498 [MM_EPG_ONLY_OPENTV_SKY_AUSAT] = "opentv-ausat",
499 };
500
501 lock_assert(&global_lock);
502
503 if (!om)
504 return;
505
506 tvhtrace(LS_EPGGRAB, "ota - kick callback");
507
508 next_one:
509 /* Find the mux */
510 mm = mpegts_mux_find(om->om_mux_uuid);
511 if (!mm) {
512 epggrab_ota_free(&epggrab_ota_pending, om);
513 goto done;
514 }
515
516 assert(om->om_q_type == EPGGRAB_OTA_MUX_PENDING);
517 TAILQ_REMOVE(&epggrab_ota_pending, om, om_q_link);
518 om->om_q_type = EPGGRAB_OTA_MUX_IDLE;
519
520 /* Check if this network failed before */
521 for (i = 0, net = NULL; i < networks_count; i++) {
522 net = &networks[i];
523 if (net->net == mm->mm_network) {
524 if (net->fatal)
525 goto done;
526 if (net->failed) {
527 TAILQ_INSERT_TAIL(&epggrab_ota_pending, om, om_q_link);
528 om->om_q_type = EPGGRAB_OTA_MUX_PENDING;
529 om->om_retry_time = mclk() + mono2sec(60);
530 goto done;
531 }
532 break;
533 }
534 }
535 if (i >= networks_count) {
536 if (i >= ARRAY_SIZE(networks)) {
537 tvherror(LS_EPGGRAB, "ota epg - too many networks");
538 goto done;
539 }
540 net = &networks[networks_count++];
541 net->net = mm->mm_network;
542 net->failed = 0;
543 net->fatal = 0;
544 }
545
546 epg_flag = MM_EPG_DISABLE;
547 if (mm->mm_is_enabled(mm)) {
548 epg_flag = mm->mm_is_epg(mm);
549 if (epg_flag > MM_EPG_LAST)
550 epg_flag = MM_EPG_ENABLE;
551 modname = epg_flag >= 0 ? modnames[epg_flag] : NULL;
552 }
553
554 if (epg_flag < 0 || epg_flag == MM_EPG_DISABLE) {
555 if (tvhtrace_enabled()) {
556 mpegts_mux_nice_name(mm, name, sizeof(name));
557 tvhtrace(LS_EPGGRAB, "epg mux %s is disabled, skipping", name);
558 }
559 goto done;
560 }
561
562 /* Check we have modules attached and enabled */
563 i = r = 0;
564 LIST_FOREACH(map, &om->om_modules, om_link) {
565 if (map->om_module->tune(map, om, mm)) {
566 i++;
567 if (modname && !strcmp(modname, map->om_module->id))
568 r = 1;
569 }
570 }
571 if ((i == 0 || (r == 0 && modname)) && epg_flag != MM_EPG_FORCE) {
572 mpegts_mux_nice_name(mm, name, sizeof(name));
573 tvhdebug(LS_EPGGRAB, "no OTA modules active for %s, check again next time", name);
574 goto done;
575 }
576
577 /* Some init stuff */
578 free(om->om_force_modname);
579 om->om_force_modname = modname ? strdup(modname) : NULL;
580
581 /* Subscribe to the mux */
582 om->om_requeue = 1;
583 if ((r = mpegts_mux_subscribe(mm, NULL, "epggrab",
584 SUBSCRIPTION_PRIO_EPG,
585 SUBSCRIPTION_EPG |
586 SUBSCRIPTION_ONESHOT |
587 SUBSCRIPTION_TABLES))) {
588 if (r != SM_CODE_NO_ADAPTERS) {
589 if (tvhtrace_enabled()) {
590 mpegts_mux_nice_name(mm, name, sizeof(name));
591 tvhtrace(LS_EPGGRAB, "subscription failed for %s (result %d)", name, r);
592 }
593 TAILQ_INSERT_TAIL(&epggrab_ota_pending, om, om_q_link);
594 om->om_q_type = EPGGRAB_OTA_MUX_PENDING;
595 om->om_retry_time = mclk() + mono2sec(60);
596 if (r == SM_CODE_NO_FREE_ADAPTER)
597 net->failed = 1;
598 if (r == SM_CODE_TUNING_FAILED)
599 net->failed = 1;
600 } else {
601 if (tvhtrace_enabled()) {
602 mpegts_mux_nice_name(mm, name, sizeof(name));
603 tvhtrace(LS_EPGGRAB, "no free adapter for %s (subscribe)", name);
604 }
605 net->fatal = 1;
606 }
607 } else {
608 if (tvhtrace_enabled()) {
609 mpegts_mux_nice_name(mm, name, sizeof(name));
610 tvhtrace(LS_EPGGRAB, "mux %s (%p), started", name, mm);
611 }
612 kick = 0;
613 /* note: it is possible that the mux_start listener is not called */
614 /* for reshared mux subscriptions, so call it (maybe second time) here.. */
615 epggrab_mux_start(mm, NULL);
616 }
617
618 done:
619 om = TAILQ_FIRST(&epggrab_ota_pending);
620 if (networks_count < ARRAY_SIZE(networks) && om && om->om_retry_time < mclk())
621 goto next_one;
622 if (kick)
623 epggrab_ota_kick(64); /* a random number? */
624
625 if (tvhtrace_enabled()) {
626 i = r = 0;
627 RB_FOREACH(om, &epggrab_ota_all, om_global_link)
628 i++;
629 TAILQ_FOREACH(om, &epggrab_ota_pending, om_q_link)
630 r++;
631 tvhtrace(LS_EPGGRAB, "mux stats - all %i pending %i", i, r);
632 }
633 }
634
635 /*
636 * Start times management
637 */
638
639 static void
640 epggrab_ota_start_cb ( void *p );
641
642 static void
epggrab_ota_next_arm(time_t next)643 epggrab_ota_next_arm( time_t next )
644 {
645 tvhtrace(LS_EPGGRAB, "next ota start event in %li seconds", next - time(NULL));
646 gtimer_arm_absn(&epggrab_ota_start_timer, epggrab_ota_start_cb, NULL, next);
647 dbus_emit_signal_s64("/epggrab/ota", "next", next);
648 }
649
650 static void
epggrab_ota_start_cb(void * p)651 epggrab_ota_start_cb ( void *p )
652 {
653 time_t next;
654
655 tvhtrace(LS_EPGGRAB, "ota start callback");
656
657 epggrab_ota_pending_flag = 1;
658
659 epggrab_ota_kick(1);
660
661 pthread_mutex_lock(&epggrab_ota_mutex);
662 if (!cron_multi_next(epggrab_ota_cron_multi, gclk(), &next))
663 epggrab_ota_next_arm(next);
664 else
665 tvhwarn(LS_EPGGRAB, "ota cron config invalid or unset");
666 pthread_mutex_unlock(&epggrab_ota_mutex);
667 }
668
669 static void
epggrab_ota_arm(time_t last)670 epggrab_ota_arm ( time_t last )
671 {
672 time_t next;
673
674 pthread_mutex_lock(&epggrab_ota_mutex);
675
676 if (!cron_multi_next(epggrab_ota_cron_multi, time(NULL), &next)) {
677 /* do not trigger the next EPG scan for 1/2 hour */
678 if (last != (time_t)-1 && last + 1800 > next)
679 next = last + 1800;
680 epggrab_ota_next_arm(next);
681 } else {
682 tvhwarn(LS_EPGGRAB, "ota cron config invalid or unset");
683 }
684
685 pthread_mutex_unlock(&epggrab_ota_mutex);
686 }
687
688 /*
689 * Service management
690 */
691
692 static void
epggrab_ota_service_trace(epggrab_ota_mux_t * ota,epggrab_ota_svc_link_t * svcl,const char * op)693 epggrab_ota_service_trace ( epggrab_ota_mux_t *ota,
694 epggrab_ota_svc_link_t *svcl,
695 const char *op )
696 {
697 char buf[256];
698 mpegts_mux_t *mm;
699 mpegts_service_t *svc;
700
701 if (!tvhtrace_enabled())
702 return;
703
704 mm = mpegts_mux_find(ota->om_mux_uuid);
705 svc = mpegts_service_find_by_uuid(svcl->uuid);
706 if (mm && svc) {
707 mpegts_mux_nice_name(mm, buf, sizeof(buf));
708 tvhtrace(LS_EPGGRAB, "ota %s %s service %s", buf, op, svc->s_nicename);
709 } else if (tvheadend_is_running())
710 tvhtrace(LS_EPGGRAB, "ota %s, problem? (%p %p)", op, mm, svc);
711 }
712
713 void
epggrab_ota_service_add(epggrab_ota_map_t * map,epggrab_ota_mux_t * ota,const char * uuid,int save)714 epggrab_ota_service_add ( epggrab_ota_map_t *map, epggrab_ota_mux_t *ota,
715 const char *uuid, int save )
716 {
717 epggrab_ota_svc_link_t *svcl;
718
719 if (uuid == NULL || !atomic_get(&epggrab_ota_running))
720 return;
721 SKEL_ALLOC(epggrab_svc_link_skel);
722 epggrab_svc_link_skel->uuid = (char *)uuid;
723 svcl = RB_INSERT_SORTED(&map->om_svcs, epggrab_svc_link_skel, link, om_svcl_cmp);
724 if (svcl == NULL) {
725 svcl = epggrab_svc_link_skel;
726 SKEL_USED(epggrab_svc_link_skel);
727 svcl->uuid = strdup(uuid);
728 if (save)
729 ota->om_save = 1;
730 epggrab_ota_service_trace(ota, svcl, "add new");
731 }
732 svcl->last_tune_count = map->om_tune_count;
733 }
734
735 void
epggrab_ota_service_del(epggrab_ota_map_t * map,epggrab_ota_mux_t * ota,epggrab_ota_svc_link_t * svcl,int save)736 epggrab_ota_service_del ( epggrab_ota_map_t *map, epggrab_ota_mux_t *ota,
737 epggrab_ota_svc_link_t *svcl, int save )
738 {
739 if (svcl == NULL || (!atomic_get(&epggrab_ota_running) && save))
740 return;
741 epggrab_ota_service_trace(ota, svcl, "delete");
742 RB_REMOVE(&map->om_svcs, svcl, link);
743 free(svcl->uuid);
744 free(svcl);
745 if (save)
746 ota->om_save = 1;
747 }
748
749 /* **************************************************************************
750 * Config
751 * *************************************************************************/
752
753 static void
epggrab_ota_save(epggrab_ota_mux_t * ota)754 epggrab_ota_save ( epggrab_ota_mux_t *ota )
755 {
756 epggrab_ota_map_t *map;
757 epggrab_ota_svc_link_t *svcl;
758 htsmsg_t *e, *l, *l2, *c = htsmsg_create_map();
759
760 ota->om_save = 0;
761 htsmsg_add_u32(c, "complete", ota->om_complete);
762 l = htsmsg_create_list();
763 LIST_FOREACH(map, &ota->om_modules, om_link) {
764 e = htsmsg_create_map();
765 htsmsg_add_str(e, "id", map->om_module->id);
766 if (RB_FIRST(&map->om_svcs)) {
767 l2 = htsmsg_create_list();
768 RB_FOREACH(svcl, &map->om_svcs, link)
769 if (svcl->uuid)
770 htsmsg_add_str(l2, NULL, svcl->uuid);
771 htsmsg_add_msg(e, "services", l2);
772 }
773 htsmsg_add_msg(l, NULL, e);
774 }
775 htsmsg_add_msg(c, "modules", l);
776 hts_settings_save(c, "epggrab/otamux/%s", ota->om_mux_uuid);
777 htsmsg_destroy(c);
778 }
779
780 static void
epggrab_ota_load_one(const char * uuid,htsmsg_t * c)781 epggrab_ota_load_one
782 ( const char *uuid, htsmsg_t *c )
783 {
784 htsmsg_t *l, *l2, *e;
785 htsmsg_field_t *f, *f2;
786 mpegts_mux_t *mm;
787 epggrab_module_ota_t *mod;
788 epggrab_ota_mux_t *ota;
789 epggrab_ota_map_t *map;
790 const char *id;
791
792 mm = mpegts_mux_find(uuid);
793 if (!mm) {
794 hts_settings_remove("epggrab/otamux/%s", uuid);
795 return;
796 }
797 if (tvhtrace_enabled()) {
798 char name[256];
799 mpegts_mux_nice_name(mm, name, sizeof(name));
800 tvhtrace(LS_EPGGRAB, "loading config for %s", name);
801 }
802
803 ota = calloc(1, sizeof(epggrab_ota_mux_t));
804 ota->om_mux_uuid = strdup(uuid);
805 if (RB_INSERT_SORTED(&epggrab_ota_all, ota, om_global_link, om_id_cmp)) {
806 free(ota->om_mux_uuid);
807 free(ota);
808 return;
809 }
810 ota->om_complete = htsmsg_get_u32_or_default(c, "complete", 0) != 0;
811
812 if (!(l = htsmsg_get_list(c, "modules"))) return;
813 HTSMSG_FOREACH(f, l) {
814 if (!(e = htsmsg_field_get_map(f))) continue;
815 if (!(id = htsmsg_get_str(e, "id"))) continue;
816 if (!(mod = (epggrab_module_ota_t*)epggrab_module_find_by_id(id)))
817 continue;
818
819 map = calloc(1, sizeof(epggrab_ota_map_t));
820 RB_INIT(&map->om_svcs);
821 map->om_module = mod;
822 if ((l2 = htsmsg_get_list(e, "services")) != NULL) {
823 HTSMSG_FOREACH(f2, l2)
824 epggrab_ota_service_add(map, ota, htsmsg_field_get_str(f2), 0);
825 }
826 LIST_INSERT_HEAD(&ota->om_modules, map, om_link);
827 }
828 }
829
830 void
epggrab_ota_init(void)831 epggrab_ota_init ( void )
832 {
833 htsmsg_t *c, *m;
834 htsmsg_field_t *f;
835 char path[1024];
836 struct stat st;
837
838 epggrab_conf.ota_initial = 1;
839 epggrab_conf.ota_timeout = 600;
840 epggrab_conf.ota_cron = strdup("# Default config (02:04 and 14:04 everyday)\n4 2 * * *\n4 14 * * *");
841 epggrab_ota_cron_multi = cron_multi_set(epggrab_conf.ota_cron);
842 epggrab_ota_pending_flag = 0;
843
844 RB_INIT(&epggrab_ota_all);
845 TAILQ_INIT(&epggrab_ota_pending);
846 TAILQ_INIT(&epggrab_ota_active);
847
848 pthread_mutex_init(&epggrab_ota_mutex, NULL);
849
850 /* Add listener */
851 static mpegts_listener_t ml = {
852 .ml_mux_start = epggrab_mux_start,
853 .ml_mux_stop = epggrab_mux_stop,
854 };
855 mpegts_add_listener(&ml);
856
857 /* Delete old config */
858 hts_settings_buildpath(path, sizeof(path), "epggrab/otamux");
859 if (!lstat(path, &st))
860 if (!S_ISDIR(st.st_mode))
861 hts_settings_remove("epggrab/otamux");
862
863 atomic_set(&epggrab_ota_running, 1);
864
865 /* Load config */
866 if ((c = hts_settings_load_r(1, "epggrab/otamux"))) {
867 HTSMSG_FOREACH(f, c) {
868 if (!(m = htsmsg_field_get_map(f))) continue;
869 epggrab_ota_load_one(f->hmf_name, m);
870 }
871 htsmsg_destroy(c);
872 }
873 }
874
875 void
epggrab_ota_trigger(int secs)876 epggrab_ota_trigger ( int secs )
877 {
878 lock_assert(&global_lock);
879
880 /* notify another system layers, that we will do EPG OTA */
881 secs = MIN(1, MAX(secs, 7*24*3600));
882 dbus_emit_signal_s64("/epggrab/ota", "next", time(NULL) + secs);
883 epggrab_ota_pending_flag = 1;
884 epggrab_ota_kick(secs);
885 }
886
887 void
epggrab_ota_post(void)888 epggrab_ota_post ( void )
889 {
890 time_t t = (time_t)-1;
891
892 /* Init timer (call after full init - wait for network tuners) */
893 if (epggrab_conf.ota_initial) {
894 epggrab_ota_trigger(15);
895 t = time(NULL);
896 }
897
898 /* arm the first scheduled time */
899 epggrab_ota_arm(t);
900 }
901
902 static void
epggrab_ota_free(epggrab_ota_head_t * head,epggrab_ota_mux_t * ota)903 epggrab_ota_free ( epggrab_ota_head_t *head, epggrab_ota_mux_t *ota )
904 {
905 epggrab_ota_map_t *map;
906 epggrab_ota_svc_link_t *svcl;
907
908 mtimer_disarm(&ota->om_timer);
909 mtimer_disarm(&ota->om_data_timer);
910 if (head != NULL)
911 TAILQ_REMOVE(head, ota, om_q_link);
912 RB_REMOVE(&epggrab_ota_all, ota, om_global_link);
913 while ((map = LIST_FIRST(&ota->om_modules)) != NULL) {
914 LIST_REMOVE(map, om_link);
915 while ((svcl = RB_FIRST(&map->om_svcs)) != NULL)
916 epggrab_ota_service_del(map, ota, svcl, 0);
917 free(map);
918 }
919 free(ota->om_mux_uuid);
920 free(ota->om_force_modname);
921 free(ota);
922 }
923
924 void
epggrab_ota_shutdown(void)925 epggrab_ota_shutdown ( void )
926 {
927 epggrab_ota_mux_t *ota;
928
929 atomic_set(&epggrab_ota_running, 0);
930 while ((ota = TAILQ_FIRST(&epggrab_ota_active)) != NULL)
931 epggrab_ota_free(&epggrab_ota_active, ota);
932 while ((ota = TAILQ_FIRST(&epggrab_ota_pending)) != NULL)
933 epggrab_ota_free(&epggrab_ota_pending, ota);
934 while ((ota = RB_FIRST(&epggrab_ota_all)) != NULL)
935 epggrab_ota_free(NULL, ota);
936 SKEL_FREE(epggrab_ota_mux_skel);
937 SKEL_FREE(epggrab_svc_link_skel);
938 free(epggrab_ota_cron_multi);
939 epggrab_ota_cron_multi = NULL;
940 }
941
942 /*
943 * Global configuration handlers
944 */
945
946 void
epggrab_ota_set_cron(void)947 epggrab_ota_set_cron ( void )
948 {
949 lock_assert(&global_lock);
950
951 pthread_mutex_lock(&epggrab_ota_mutex);
952 free(epggrab_ota_cron_multi);
953 epggrab_ota_cron_multi = cron_multi_set(epggrab_conf.ota_cron);
954 pthread_mutex_unlock(&epggrab_ota_mutex);
955 epggrab_ota_arm((time_t)-1);
956 }
957
958 /******************************************************************************
959 * Editor Configuration
960 *
961 * vim:sts=2:ts=2:sw=2:et
962 *****************************************************************************/
963