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