1 /*
2  *  Tvheadend - SAT-IP client
3  *
4  *  Copyright (C) 2014 Jaroslav Kysela
5  *
6  *  This program is free software: you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation, either version 3 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include "tvheadend.h"
21 #include "input.h"
22 #include "htsbuf.h"
23 #include "htsmsg_xml.h"
24 #include "upnp.h"
25 #include "settings.h"
26 #include "satip/server.h"
27 #include "satip_private.h"
28 #include "dbus.h"
29 
30 #include <arpa/inet.h>
31 #include <openssl/sha.h>
32 
33 #if defined(PLATFORM_FREEBSD) || ENABLE_ANDROID
34 #include <sys/types.h>
35 #include <sys/socket.h>
36 #endif
37 
38 static void satip_discovery_timer_cb(void *aux);
39 
40 /*
41  *
42  */
43 
44 static void
satip_device_dbus_notify(satip_device_t * sd,const char * sig_name)45 satip_device_dbus_notify( satip_device_t *sd, const char *sig_name )
46 {
47 #if ENABLE_DBUS_1
48   char buf[256], ubuf[UUID_HEX_SIZE];
49 
50   htsmsg_t *msg = htsmsg_create_list();
51   htsmsg_add_str(msg, NULL, sd->sd_info.addr);
52   htsmsg_add_str(msg, NULL, sd->sd_info.location);
53   htsmsg_add_str(msg, NULL, sd->sd_info.server);
54   htsmsg_add_s64(msg, NULL, sd->sd_info.rtsp_port);
55   snprintf(buf, sizeof(buf), "/input/mpegts/satip/%s", idnode_uuid_as_str(&sd->th_id, ubuf));
56   dbus_emit_signal(buf, sig_name, msg);
57 #endif
58 }
59 
60 static void
satip_device_block(const char * addr,int block)61 satip_device_block( const char *addr, int block )
62 {
63   extern const idclass_t satip_device_class;
64   tvh_hardware_t *th;
65   satip_device_t *sd;
66   satip_frontend_t *lfe;
67   int val = block < 0 ? 0 : block;
68 
69   pthread_mutex_lock(&global_lock);
70   TVH_HARDWARE_FOREACH(th) {
71     if (!idnode_is_instance(&th->th_id, &satip_device_class))
72       continue;
73     sd = (satip_device_t *)th;
74     if (strcmp(sd->sd_info.addr, addr) == 0 && val != sd->sd_dbus_allow) {
75       sd->sd_dbus_allow = val;
76       if (block < 0) {
77         TAILQ_FOREACH(lfe, &sd->sd_frontends, sf_link)
78           mpegts_input_stop_all((mpegts_input_t *)lfe);
79       }
80       tvhinfo(LS_SATIP, "address %s is %s", addr,
81               block < 0 ? "stopped" : (block > 0 ? "allowed" : "disabled"));
82     }
83   }
84   pthread_mutex_unlock(&global_lock);
85 }
86 
87 static char *
satip_device_addr(void * aux,const char * path,char * value)88 satip_device_addr( void *aux, const char *path, char *value )
89 {
90   if (strcmp(path, "/stop") == 0) {
91     satip_device_block(value, -1);
92     return strdup("ok");
93   } else if (strcmp(path, "/disable") == 0) {
94     satip_device_block(value, 0);
95     return strdup("ok");
96   } else if (strcmp(path, "/allow") == 0) {
97     satip_device_block(value, 1);
98     return strdup("ok");
99   }
100   return strdup("err");
101 }
102 
103 /*
104  *
105  */
106 char *
satip_device_nicename(satip_device_t * sd,char * buf,int len)107 satip_device_nicename( satip_device_t *sd, char *buf, int len )
108 {
109   if (sd->sd_info.rtsp_port != 554)
110     snprintf(buf, len, "%s:%d", sd->sd_info.addr, sd->sd_info.rtsp_port);
111   else
112     snprintf(buf, len, "%s", sd->sd_info.addr);
113   return buf;
114 }
115 
116 /*
117  * SAT-IP client
118  */
119 
120 static htsmsg_t *
satip_device_class_save(idnode_t * in,char * filename,size_t fsize)121 satip_device_class_save ( idnode_t *in, char *filename, size_t fsize )
122 {
123   satip_device_t *sd = (satip_device_t *)in;
124   satip_frontend_t *lfe;
125   htsmsg_t *m, *l;
126   char ubuf[UUID_HEX_SIZE];
127 
128   if (sd->sd_nosave)
129     return NULL;
130 
131   m = htsmsg_create_map();
132   idnode_save(&sd->th_id, m);
133 
134   l = htsmsg_create_map();
135   TAILQ_FOREACH(lfe, &sd->sd_frontends, sf_link)
136     satip_frontend_save(lfe, l);
137   htsmsg_add_msg(m, "frontends", l);
138 
139   snprintf(filename, fsize, "input/satip/adapters/%s",
140            idnode_uuid_as_str(&sd->th_id, ubuf));
141   return m;
142 }
143 
144 static const void *
satip_device_class_active_get(void * obj)145 satip_device_class_active_get ( void * obj )
146 {
147   static int active;
148   satip_device_t *sd = (satip_device_t *)obj;
149   satip_frontend_t *lfe;
150   active = 0;
151   TAILQ_FOREACH(lfe, &sd->sd_frontends, sf_link)
152     if (*(int *)mpegts_input_class_active_get(lfe)) {
153       active = 1;
154       break;
155     }
156   return &active;
157 }
158 
159 static idnode_set_t *
satip_device_class_get_childs(idnode_t * in)160 satip_device_class_get_childs ( idnode_t *in )
161 {
162   satip_device_t *sd = (satip_device_t *)in;
163   idnode_set_t *is = idnode_set_create(0);
164   satip_frontend_t *lfe;
165 
166   TAILQ_FOREACH(lfe, &sd->sd_frontends, sf_link)
167     idnode_set_add(is, &lfe->ti_id, NULL, NULL);
168   return is;
169 }
170 
171 static const char *
satip_device_class_get_title(idnode_t * in,const char * lang)172 satip_device_class_get_title( idnode_t *in, const char *lang )
173 {
174   static char buf[256];
175   satip_device_t *sd = (satip_device_t *)in;
176   snprintf(buf, sizeof(buf),
177            "%s - %s", sd->sd_info.friendlyname, sd->sd_info.addr);
178   return buf;
179 }
180 
181 static const char *satip_tunercfg_tab[] = {
182   "DVBS2-1",
183   "DVBS2-2",
184   "DVBS2-4",
185   "DVBS2-8",
186   "DVBC-1",
187   "DVBC-2",
188   "DVBC-4",
189   "DVBC-8",
190   "DVBT-1",
191   "DVBT-2",
192   "DVBT-4",
193   "DVBT-8",
194   "DVBS2-1,DVBT-1",
195   "DVBS2-2,DVBT-2",
196   "DVBT-1,DVBS2-1",
197   "DVBT-2,DVBS2-2",
198   "DVBS2-1,DVB-C1",
199   "DVBS2-2,DVB-C2",
200   "DVBC-1,DVBS2-1",
201   "DVBC-2,DVBS2-2",
202   NULL
203 };
204 
205 static htsmsg_t *
satip_device_class_tunercfg_list(void * o,const char * lang)206 satip_device_class_tunercfg_list ( void *o, const char *lang )
207 {
208   htsmsg_t *l = htsmsg_create_list();
209   const char **p;
210   htsmsg_add_str(l, NULL, "Auto");
211   for (p = satip_tunercfg_tab; *p; p++)
212     htsmsg_add_str(l, NULL, *p);
213   return l;
214 }
215 
216 static void
satip_device_class_tunercfg_notify(void * o,const char * lang)217 satip_device_class_tunercfg_notify ( void *o, const char *lang )
218 {
219   satip_device_t *sd = (satip_device_t *)o;
220   if (!sd->sd_inload)
221     satip_device_destroy_later(sd, 100);
222 }
223 
224 CLASS_DOC(satip_client)
225 
226 const idclass_t satip_device_class =
227 {
228   .ic_class      = "satip_client",
229   .ic_event      = "satip_client",
230   .ic_caption    = N_("SAT>IP Client"),
231   .ic_doc        = tvh_doc_satip_client_class,
232   .ic_save       = satip_device_class_save,
233   .ic_get_childs = satip_device_class_get_childs,
234   .ic_get_title  = satip_device_class_get_title,
235   .ic_properties = (const property_t[]){
236     {
237       .type     = PT_BOOL,
238       .id       = "active",
239       .name     = N_("Active"),
240       .opts     = PO_RDONLY | PO_NOSAVE | PO_NOUI,
241       .get      = satip_device_class_active_get,
242     },
243     {
244       .type     = PT_STR,
245       .id       = "tunercfgu",
246       .name     = N_("Tuner configuration"),
247       .desc     = N_("Tuner configuration."),
248       .opts     = PO_SORTKEY,
249       .off      = offsetof(satip_device_t, sd_tunercfg),
250       .list     = satip_device_class_tunercfg_list,
251       .notify   = satip_device_class_tunercfg_notify,
252       .def.s    = "Auto"
253     },
254     {
255       .type     = PT_BOOL,
256       .id       = "tcp_mode",
257       .name     = N_("RTP/AVP/TCP (embedded data)"),
258       .desc     = N_("Enable or disable RTP/AVP/TCP transfer mode "
259                      "(embedded data in the RTSP session) support."),
260       .opts     = PO_ADVANCED,
261       .off      = offsetof(satip_device_t, sd_tcp_mode),
262     },
263     {
264       .type     = PT_BOOL,
265       .id       = "fast_switch",
266       .name     = N_("Fast input switch"),
267       .desc     = N_("Enable or disable fast input switching."),
268       .opts     = PO_ADVANCED,
269       .off      = offsetof(satip_device_t, sd_fast_switch),
270     },
271     {
272       .type     = PT_BOOL,
273       .id       = "fullmux_ok",
274       .name     = N_("Full mux RX mode supported"),
275       .desc     = N_("Enable or disable full mux mode."),
276       .opts     = PO_ADVANCED,
277       .off      = offsetof(satip_device_t, sd_fullmux_ok),
278     },
279     {
280       .type     = PT_INT,
281       .id       = "sigscale",
282       .name     = N_("Signal scale (240 or 100)"),
283       .desc     = N_("Not all SAT>IP servers use the same signal scaling. "
284                      "Change this setting if the signal level displayed "
285                      "within Tvheadend looks too low."),
286       .opts     = PO_ADVANCED,
287       .off      = offsetof(satip_device_t, sd_sig_scale),
288     },
289     {
290       .type     = PT_INT,
291       .id       = "pids_max",
292       .name     = N_("Maximum PIDs"),
293       .desc     = N_("Set the maxiumum packet identifiers your SAT>IP "
294                      "server supports."),
295       .opts     = PO_ADVANCED,
296       .off      = offsetof(satip_device_t, sd_pids_max),
297     },
298     {
299       .type     = PT_INT,
300       .id       = "pids_len",
301       .name     = N_("Maximum length of PIDs"),
302       .desc     = N_("Maximum length in characters for the command "
303                      "setting PIDs to the SAT>IP box."),
304       .opts     = PO_ADVANCED,
305       .off      = offsetof(satip_device_t, sd_pids_len),
306     },
307     {
308       .type     = PT_BOOL,
309       .id       = "pids_deladd",
310       .name     = N_("addpids/delpids supported"),
311       .desc     = N_("Enable if the SAT>IP box supports the "
312                      "addpids/delpids commands."),
313       .opts     = PO_ADVANCED,
314       .off      = offsetof(satip_device_t, sd_pids_deladd),
315     },
316     {
317       .type     = PT_BOOL,
318       .id       = "fe",
319       .name     = N_("FE supported"),
320       .desc     = N_("Enable if the SAT>IP box supports the frontend "
321                      "identifier. This allows the auto-tuner allocation, "
322                      "but it might cause trouble for boxes with different "
323                      "tuner reception connections like satellite inputs."),
324       .opts     = PO_ADVANCED,
325       .off      = offsetof(satip_device_t, sd_fe),
326     },
327     {
328       .type     = PT_BOOL,
329       .id       = "piloton",
330       .name     = N_("Force pilot for DVB-S2"),
331       .desc     = N_("Enable if the SAT>IP box requests plts=on "
332                      "parameter in the SETUP RTSP command for DVB-S2 "
333                      "muxes."),
334       .opts     = PO_ADVANCED,
335       .off      = offsetof(satip_device_t, sd_pilot_on),
336     },
337     {
338       .type     = PT_BOOL,
339       .id       = "pids21",
340       .name     = N_("PIDs 21 in setup"),
341       .desc     = N_("Enable if the SAT>IP box requires pids=21 "
342                      "parameter in the SETUP RTSP command"),
343       .opts     = PO_ADVANCED,
344       .off      = offsetof(satip_device_t, sd_pids21),
345     },
346     {
347       .type     = PT_STR,
348       .id       = "bindaddr",
349       .name     = N_("Local bind IP address"),
350       .desc     = N_("Bind to specific local IP address."),
351       .opts     = PO_ADVANCED,
352       .off      = offsetof(satip_device_t, sd_bindaddr),
353     },
354     {
355       .type     = PT_INT,
356       .id       = "skip_ts",
357       .name     = N_("Skip TS packets (0-200)"),
358       .desc     = N_("Skip x number of transport packets."),
359       .opts     = PO_EXPERT,
360       .off      = offsetof(satip_device_t, sd_skip_ts),
361     },
362     {
363       .type     = PT_BOOL,
364       .id       = "disableworkarounds",
365       .name     = N_("Disable device/firmware-specific workarounds"),
366       .opts     = PO_ADVANCED,
367       .off      = offsetof(satip_device_t, sd_disable_workarounds),
368     },
369     {
370       .type     = PT_STR,
371       .id       = "addr",
372       .name     = N_("IP address"),
373       .desc     = N_("Force all network connections to this tuner to be "
374                      "made over the specified IP address, similar to "
375                      "the setting for the SAT>IP device itself. Setting "
376                      "this overrides the device-specific setting."),
377       .opts     = PO_RDONLY | PO_NOSAVE,
378       .off      = offsetof(satip_device_t, sd_info.addr),
379     },
380     {
381       .type     = PT_INT,
382       .id       = "rtsp",
383       .name     = N_("RTSP port"),
384       .desc     = N_("Current RTSP port."),
385       .opts     = PO_RDONLY | PO_NOSAVE,
386       .off      = offsetof(satip_device_t, sd_info.rtsp_port),
387     },
388     {
389       .type     = PT_STR,
390       .id       = "device_uuid",
391       .name     = N_("UUID"),
392       .desc     = N_("The SAT>IP server's universally unique identifier."),
393       .opts     = PO_RDONLY,
394       .off      = offsetof(satip_device_t, sd_info.uuid),
395     },
396     {
397       .type     = PT_STR,
398       .id       = "friendly",
399       .name     = N_("Friendly name"),
400       .desc     = N_("The SAT>IP server's name."),
401       .opts     = PO_RDONLY | PO_NOSAVE,
402       .off      = offsetof(satip_device_t, sd_info.friendlyname),
403     },
404     {
405       .type     = PT_STR,
406       .id       = "serialnum",
407       .name     = N_("Serial number"),
408       .desc     = N_("The device's serial number."),
409       .opts     = PO_RDONLY | PO_NOSAVE,
410       .off      = offsetof(satip_device_t, sd_info.serialnum),
411     },
412     {
413       .type     = PT_STR,
414       .id       = "tunercfg",
415       .name     = N_("Tuner configuration"),
416       .desc     = N_("Current tuner configuration."),
417       .opts     = PO_RDONLY | PO_NOSAVE,
418       .off      = offsetof(satip_device_t, sd_info.tunercfg),
419     },
420     {
421       .type     = PT_STR,
422       .id       = "manufacturer",
423       .name     = N_("Manufacturer"),
424       .desc     = N_("The manufacturer of the SAT>IP server."),
425       .opts     = PO_RDONLY | PO_NOSAVE,
426       .off      = offsetof(satip_device_t, sd_info.manufacturer),
427     },
428     {
429       .type     = PT_STR,
430       .id       = "manufurl",
431       .name     = N_("Manufacturer URL"),
432       .desc     = N_("Manufacturer's product information page for the device."),
433       .opts     = PO_RDONLY | PO_NOSAVE,
434       .off      = offsetof(satip_device_t, sd_info.manufacturerURL),
435     },
436     {
437       .type     = PT_STR,
438       .id       = "modeldesc",
439       .name     = N_("Model description"),
440       .desc     = N_("Manufacturer's product description."),
441       .opts     = PO_RDONLY | PO_NOSAVE,
442       .off      = offsetof(satip_device_t, sd_info.modeldesc),
443     },
444     {
445       .type     = PT_STR,
446       .id       = "modelname",
447       .name     = N_("Model name"),
448       .desc     = N_("Manufacturer's product name."),
449       .opts     = PO_RDONLY | PO_NOSAVE,
450       .off      = offsetof(satip_device_t, sd_info.modelname),
451     },
452     {
453       .type     = PT_STR,
454       .id       = "modelnum",
455       .name     = N_("Model number"),
456       .desc     = N_("Manufacturer's model number."),
457       .opts     = PO_RDONLY | PO_NOSAVE,
458       .off      = offsetof(satip_device_t, sd_info.modelnum),
459     },
460     {
461       .type     = PT_STR,
462       .id       = "bootid",
463       .name     = N_("Boot ID"),
464       .desc     = N_("The current boot ID."),
465       .opts     = PO_RDONLY | PO_NOSAVE,
466       .off      = offsetof(satip_device_t, sd_info.bootid),
467     },
468     {
469       .type     = PT_STR,
470       .id       = "configid",
471       .name     = N_("Configuration ID"),
472       .desc     = N_("The current configuration ID."),
473       .opts     = PO_RDONLY | PO_NOSAVE,
474       .off      = offsetof(satip_device_t, sd_info.configid),
475     },
476     {
477       .type     = PT_STR,
478       .id       = "deviceid",
479       .name     = N_("Device ID"),
480       .desc     = N_("The device ID."),
481       .opts     = PO_RDONLY | PO_NOSAVE,
482       .off      = offsetof(satip_device_t, sd_info.deviceid),
483     },
484     {
485       .type     = PT_STR,
486       .id       = "presentation",
487       .name     = N_("Presentation"),
488       .desc     = N_("Presentation details."),
489       .opts     = PO_RDONLY | PO_NOSAVE,
490       .off      = offsetof(satip_device_t, sd_info.presentation),
491     },
492     {
493       .type     = PT_STR,
494       .id       = "location",
495       .name     = N_("Location"),
496       .desc     = N_("Location details of the SAT>IP Server."),
497       .opts     = PO_RDONLY | PO_NOSAVE,
498       .off      = offsetof(satip_device_t, sd_info.location),
499     },
500     {
501       .type     = PT_STR,
502       .id       = "server",
503       .name     = N_("Server"),
504       .desc     = N_("Server details."),
505       .opts     = PO_RDONLY | PO_NOSAVE,
506       .off      = offsetof(satip_device_t, sd_info.server),
507     },
508     {
509       .type     = PT_STR,
510       .id       = "myaddr",
511       .name     = N_("Local discovery IP address"),
512       .desc     = N_("The SAT>IP's discovered IP address."),
513       .opts     = PO_RDONLY | PO_NOSAVE,
514       .off      = offsetof(satip_device_t, sd_info.myaddr),
515     },
516     {}
517   }
518 };
519 
520 /*
521  * Create entry
522  */
523 static void
satip_device_calc_bin_uuid(uint8_t * uuid,const char * satip_uuid)524 satip_device_calc_bin_uuid( uint8_t *uuid, const char *satip_uuid )
525 {
526   SHA_CTX sha1;
527 
528   SHA1_Init(&sha1);
529   SHA1_Update(&sha1, (void*)satip_uuid, strlen(satip_uuid));
530   SHA1_Final(uuid, &sha1);
531 }
532 
533 static void
satip_device_calc_uuid(tvh_uuid_t * uuid,const char * satip_uuid)534 satip_device_calc_uuid( tvh_uuid_t *uuid, const char *satip_uuid )
535 {
536   uint8_t uuidbin[20];
537 
538   sha1_calc(uuidbin, (const uint8_t *)satip_uuid, strlen(satip_uuid), NULL, 0);
539   bin2hex(uuid->hex, sizeof(uuid->hex), uuidbin, sizeof(uuidbin));
540 }
541 
542 static void
satip_device_hack(satip_device_t * sd)543 satip_device_hack( satip_device_t *sd )
544 {
545   if(sd->sd_disable_workarounds)
546       return;
547 #if 0
548   /* V1.24.0.156 cannot be distinguished from V1.13.0.105 :-( */
549   /* hopefully, all users have V1.16.0.120+ now */
550   if (sd->sd_info.deviceid[0] &&
551       strcmp(sd->sd_info.server, "Linux/1.0 UPnP/1.1 IDL4K/1.0") == 0) {
552     /* AXE Linux distribution - Inverto firmware */
553     /* version V1.13.0.105 and probably less */
554     /* really ugly firmware - soooooo much restrictions */
555     sd->sd_fullmux_ok  = 0;
556     sd->sd_pids_max    = 32;
557     sd->sd_pids_deladd = 0;
558     tvhwarn(LS_SATIP, "Detected old Inverto firmware V1.13.0.105 and less");
559     tvhwarn(LS_SATIP, "Upgrade to V1.16.0.120 - http://http://www.inverto.tv/support/ - IDL400s");
560   } else
561 #endif
562   if (strstr(sd->sd_info.location, ":8888/octonet.xml")) {
563     /* OctopusNet requires pids in the SETUP RTSP command */
564   } else if (strstr(sd->sd_info.manufacturer, "Triax") &&
565              strstr(sd->sd_info.modelname, "TSS400")) {
566     sd->sd_fullmux_ok  = 0;
567     sd->sd_pids_max    = 64;
568     sd->sd_pilot_on    = 1;
569   } else if (strcmp(sd->sd_info.modelname, "TVHeadend SAT>IP") == 0)  {
570     sd->sd_pids_max    = 128;
571     sd->sd_pids_len    = 2048;
572     sd->sd_no_univ_lnb = 1;
573     if (strcmp(sd->sd_info.modelnum ?: "", "1.0"))
574       sd->sd_can_weight  = 1;
575   } else if (strstr(sd->sd_info.manufacturer, "AVM Berlin") &&
576              strstr(sd->sd_info.modelname, "FRITZ!")) {
577     sd->sd_fullmux_ok  = 0;
578     sd->sd_pids_deladd = 0;
579     sd->sd_pids21      = 1;
580   } else if (strstr(sd->sd_info.modelname, "EyeTV Netstream 4C")) {
581     sd->sd_fe  = 0;
582   }
583 }
584 
585 static satip_device_t *
satip_device_create(satip_device_info_t * info)586 satip_device_create( satip_device_info_t *info )
587 {
588   satip_device_t *sd = calloc(1, sizeof(satip_device_t));
589   tvh_uuid_t uuid;
590   htsmsg_t *conf = NULL, *feconf = NULL;
591   char *argv[10], *tunercfg;
592   int i, j, n, m, fenum, v2, save = 0;
593   dvb_fe_type_t type;
594   char buf2[60];
595 
596   sd->sd_inload = 1;
597 
598   satip_device_calc_uuid(&uuid, info->uuid);
599 
600   conf = hts_settings_load("input/satip/adapters/%s", uuid.hex);
601 
602   /* some sane defaults */
603   sd->sd_fast_switch = 1;
604   sd->sd_fullmux_ok  = 1;
605   sd->sd_pids_len    = 127;
606   sd->sd_pids_max    = 32;
607   sd->sd_pids_deladd = 1;
608   sd->sd_fe          = 1;
609   sd->sd_sig_scale   = 240;
610   sd->sd_dbus_allow  = 1;
611 
612   if (!tvh_hardware_create0((tvh_hardware_t*)sd, &satip_device_class,
613                             uuid.hex, conf)) {
614     /* Note: sd is freed in above fcn */
615     return NULL;
616   }
617 
618   pthread_mutex_init(&sd->sd_tune_mutex, NULL);
619 
620   TAILQ_INIT(&sd->sd_frontends);
621   TAILQ_INIT(&sd->sd_serialize_queue);
622 
623   atomic_set(&sd->sd_wake_ref, 0);
624 
625   /* we may check if uuid matches, but the SHA hash should be enough */
626   if (sd->sd_info.uuid)
627     free(sd->sd_info.uuid);
628 
629 #define ASSIGN(x) sd->sd_info.x = info->x; info->x = NULL
630   ASSIGN(myaddr);
631   ASSIGN(addr);
632   ASSIGN(uuid);
633   ASSIGN(bootid);
634   ASSIGN(configid);
635   ASSIGN(deviceid);
636   ASSIGN(server);
637   ASSIGN(location);
638   ASSIGN(friendlyname);
639   ASSIGN(manufacturer);
640   ASSIGN(manufacturerURL);
641   ASSIGN(modeldesc);
642   ASSIGN(modelname);
643   ASSIGN(modelnum);
644   ASSIGN(serialnum);
645   ASSIGN(presentation);
646   ASSIGN(tunercfg);
647 #undef ASSIGN
648   sd->sd_info.rtsp_port = info->rtsp_port;
649   sd->sd_info.srcs = info->srcs;
650 
651   /*
652    * device specific hacks
653    */
654   satip_device_hack(sd);
655 
656   if (conf)
657     feconf = htsmsg_get_map(conf, "frontends");
658   save = !conf || !feconf;
659 
660   tunercfg = sd->sd_tunercfg;
661   if (tunercfg == NULL)
662     tunercfg = sd->sd_tunercfg = strdup("Auto");
663   if (strncmp(tunercfg, "DVB", 3) && strncmp(tunercfg, "ATSC", 4))
664     tunercfg = sd->sd_info.tunercfg;
665 
666   n = http_tokenize(tvh_strdupa(tunercfg), argv, 10, ',');
667   for (i = m = 0, fenum = 1; i < n; i++) {
668     type = DVB_TYPE_NONE;
669     v2 = 0;
670     if (strncmp(argv[i], "DVBS2-", 6) == 0) {
671       type = DVB_TYPE_S;
672       m = atoi(argv[i] + 6);
673       v2 = 1;
674     } else if (strncmp(argv[i], "DVBS-", 5) == 0) {
675       type = DVB_TYPE_S;
676       m = atoi(argv[i] + 5);
677     } else if (strncmp(argv[i], "DVBT2-", 6) == 0) {
678       type = DVB_TYPE_T;
679       m = atoi(argv[i] + 6);
680       v2 = 1;
681     } else if (strncmp(argv[i], "DVBT-", 5) == 0) {
682       type = DVB_TYPE_T;
683       m = atoi(argv[i] + 5);
684     } else if (strncmp(argv[i], "DVBC2-", 6) == 0) {
685       type = DVB_TYPE_C;
686       m = atoi(argv[i] + 6);
687       v2 = 1;
688     } else if (strncmp(argv[i], "DVBC-", 5) == 0) {
689       type = DVB_TYPE_C;
690       m = atoi(argv[i] + 5);
691     } else if (strncmp(argv[i], "ATSCT-", 6) == 0) {
692       type = DVB_TYPE_ATSC_T;
693       m = atoi(argv[i] + 6);
694     } else if (strncmp(argv[i], "ATSCC-", 6) == 0) {
695       type = DVB_TYPE_ATSC_C;
696       m = atoi(argv[i] + 6);
697     }
698     if (type == DVB_TYPE_NONE) {
699       tvherror(LS_SATIP, "%s: bad tuner type [%s]",
700                satip_device_nicename(sd, buf2, sizeof(buf2)), argv[i]);
701     } else if (m < 0 || m > 32) {
702       tvherror(LS_SATIP, "%s: bad tuner count [%s]",
703                satip_device_nicename(sd, buf2, sizeof(buf2)), argv[i]);
704     } else {
705       sd->sd_nosave = 1;
706       for (j = 0; j < m; j++)
707         if (satip_frontend_create(feconf, sd, type, v2, fenum))
708           fenum++;
709       sd->sd_nosave = 0;
710     }
711   }
712 
713   if (save)
714     satip_device_changed(sd);
715 
716   sd->sd_inload = 0;
717 
718   htsmsg_destroy(conf);
719 
720   satip_device_dbus_notify(sd, "start");
721 
722   return sd;
723 }
724 
725 static satip_device_t *
satip_device_find(const char * satip_uuid)726 satip_device_find( const char *satip_uuid )
727 {
728   tvh_hardware_t *th;
729   uint8_t binuuid[20];
730 
731   satip_device_calc_bin_uuid(binuuid, satip_uuid);
732   TVH_HARDWARE_FOREACH(th) {
733     if (idnode_is_instance(&th->th_id, &satip_device_class) &&
734         memcmp(th->th_id.in_uuid.bin, binuuid, UUID_BIN_SIZE) == 0)
735       return (satip_device_t *)th;
736   }
737   return NULL;
738 }
739 
740 static satip_device_t *
satip_device_find_by_descurl(const char * descurl)741 satip_device_find_by_descurl( const char *descurl )
742 {
743   tvh_hardware_t *th;
744 
745   TVH_HARDWARE_FOREACH(th) {
746     if (idnode_is_instance(&th->th_id, &satip_device_class) &&
747         strcmp(((satip_device_t *)th)->sd_info.location, descurl) == 0)
748       return (satip_device_t *)th;
749   }
750   return NULL;
751 }
752 
753 void
satip_device_destroy(satip_device_t * sd)754 satip_device_destroy( satip_device_t *sd )
755 {
756   satip_frontend_t *lfe;
757 
758   lock_assert(&global_lock);
759 
760   mtimer_disarm(&sd->sd_destroy_timer);
761 
762   idnode_save_check(&sd->th_id, 0);
763 
764   while ((lfe = TAILQ_FIRST(&sd->sd_frontends)) != NULL)
765     satip_frontend_delete(lfe);
766 
767   satip_device_dbus_notify(sd, "stop");
768 
769 #define FREEM(x) free(sd->sd_info.x)
770   FREEM(myaddr);
771   FREEM(addr);
772   FREEM(uuid);
773   FREEM(bootid);
774   FREEM(configid);
775   FREEM(deviceid);
776   FREEM(location);
777   FREEM(server);
778   FREEM(friendlyname);
779   FREEM(manufacturer);
780   FREEM(manufacturerURL);
781   FREEM(modeldesc);
782   FREEM(modelname);
783   FREEM(modelnum);
784   FREEM(serialnum);
785   FREEM(presentation);
786   FREEM(tunercfg);
787 #undef FREEM
788   free(sd->sd_bindaddr);
789   free(sd->sd_tunercfg);
790 
791   tvh_hardware_delete((tvh_hardware_t*)sd);
792   free(sd);
793 }
794 
795 static void
satip_device_destroy_cb(void * aux)796 satip_device_destroy_cb( void *aux )
797 {
798   satip_device_destroy((satip_device_t *)aux);
799   satip_device_discovery_start();
800 }
801 
802 void
satip_device_destroy_later(satip_device_t * sd,int after)803 satip_device_destroy_later( satip_device_t *sd, int after )
804 {
805   mtimer_arm_rel(&sd->sd_destroy_timer, satip_device_destroy_cb, sd, ms2mono(after));
806 }
807 
808 /*
809  * Discovery job
810  */
811 
812 typedef struct satip_discovery {
813   TAILQ_ENTRY(satip_discovery) disc_link;
814   char *myaddr;
815   char *location;
816   char *server;
817   char *uuid;
818   char *bootid;
819   char *configid;
820   char *deviceid;
821   url_t url;
822   http_client_t *http_client;
823   int64_t http_start;
824 } satip_discovery_t;
825 
826 TAILQ_HEAD(satip_discovery_queue, satip_discovery);
827 
828 static int satip_enabled;
829 static int satip_discoveries_count;
830 static struct satip_discovery_queue satip_discoveries;
831 static upnp_service_t *satip_discovery_service;
832 static mtimer_t satip_discovery_timer;
833 static mtimer_t satip_discovery_static_timer;
834 static mtimer_t satip_discovery_timerq;
835 static mtimer_t satip_discovery_msearch_timer;
836 static str_list_t *satip_static_clients;
837 
838 static void
satip_discovery_destroy(satip_discovery_t * d,int unlink)839 satip_discovery_destroy(satip_discovery_t *d, int unlink)
840 {
841   if (d == NULL)
842     return;
843   if (unlink) {
844     atomic_dec(&satip_discoveries_count, 1);
845     TAILQ_REMOVE(&satip_discoveries, d, disc_link);
846   }
847   if (d->http_client)
848     http_client_close(d->http_client);
849   urlreset(&d->url);
850   free(d->myaddr);
851   free(d->location);
852   free(d->server);
853   free(d->uuid);
854   free(d->bootid);
855   free(d->configid);
856   free(d->deviceid);
857   free(d);
858 }
859 
860 static satip_discovery_t *
satip_discovery_find(satip_discovery_t * d)861 satip_discovery_find(satip_discovery_t *d)
862 {
863   satip_discovery_t *sd;
864 
865   TAILQ_FOREACH(sd, &satip_discoveries, disc_link)
866     if (strcmp(sd->uuid, d->uuid) == 0)
867       return sd;
868   return NULL;
869 }
870 
871 static void
satip_discovery_http_closed(http_client_t * hc,int errn)872 satip_discovery_http_closed(http_client_t *hc, int errn)
873 {
874   satip_discovery_t *d = hc->hc_aux;
875   char *s;
876   htsmsg_t *xml = NULL, *tags, *root, *device;
877   const char *friendlyname, *manufacturer, *manufacturerURL, *modeldesc;
878   const char *modelname, *modelnum, *serialnum;
879   const char *presentation, *tunercfg, *udn, *uuid;
880   const char *cs, *arg;
881   satip_device_info_t info;
882   char errbuf[100];
883   char *argv[10];
884   int i, n;
885 
886   s = http_arg_get(&hc->hc_args, "Content-Type");
887   if (s) {
888     n = http_tokenize(s, argv, ARRAY_SIZE(argv), ';');
889     if (n <= 0 || strcasecmp(s, "text/xml")) {
890       errn = ENOENT;
891       s = NULL;
892     }
893   }
894   if (errn != 0 || s == NULL || hc->hc_code != 200 ||
895       hc->hc_data_size == 0 || hc->hc_data == NULL) {
896     tvherror(LS_SATIP, "Cannot get %s: %s", d->location, strerror(errn));
897     return;
898   }
899 
900   if (tvhtrace_enabled()) {
901     tvhtrace(LS_SATIP, "received XML description from %s", hc->hc_host);
902     tvhlog_hexdump(LS_SATIP, hc->hc_data, hc->hc_data_size);
903   }
904 
905   if (d->myaddr == NULL || d->myaddr[0] == '\0') {
906     struct sockaddr_storage ip;
907     socklen_t addrlen = sizeof(ip);
908     errbuf[0] = '\0';
909     getsockname(hc->hc_fd, (struct sockaddr *)&ip, &addrlen);
910     inet_ntop(ip.ss_family, IP_IN_ADDR(ip), errbuf, sizeof(errbuf));
911     free(d->myaddr);
912     d->myaddr = strdup(errbuf);
913   }
914 
915   s = hc->hc_data + hc->hc_data_size - 1;
916   while (s != hc->hc_data && *s != '/')
917     s--;
918   if (s != hc->hc_data)
919     s--;
920   if (strncmp(s, "</root>", 7))
921     return;
922   /* Parse */
923   xml = htsmsg_xml_deserialize(hc->hc_data, errbuf, sizeof(errbuf));
924   hc->hc_data = NULL;
925   if (!xml) {
926     tvherror(LS_SATIP, "satip_discovery_desc htsmsg_xml_deserialize error %s", errbuf);
927     goto finish;
928   }
929   if ((tags         = htsmsg_get_map(xml, "tags")) == NULL)
930     goto finish;
931   if ((root         = htsmsg_get_map(tags, "root")) == NULL)
932     goto finish;
933   if ((device       = htsmsg_get_map(root, "tags")) == NULL)
934     goto finish;
935   if ((device       = htsmsg_get_map(device, "device")) == NULL)
936     goto finish;
937   if ((device       = htsmsg_get_map(device, "tags")) == NULL)
938     goto finish;
939   if ((cs           = htsmsg_xml_get_cdata_str(device, "deviceType")) == NULL)
940     goto finish;
941   if (strcmp(cs, "urn:ses-com:device:SatIPServer:1"))
942     goto finish;
943   if ((friendlyname = htsmsg_xml_get_cdata_str(device, "friendlyName")) == NULL)
944     goto finish;
945   if ((manufacturer = htsmsg_xml_get_cdata_str(device, "manufacturer")) == NULL)
946     manufacturer = "";
947   if ((manufacturerURL = htsmsg_xml_get_cdata_str(device, "manufacturerURL")) == NULL)
948     manufacturerURL = "";
949   if ((modeldesc    = htsmsg_xml_get_cdata_str(device, "modelDescription")) == NULL)
950     modeldesc = "";
951   if ((modelname    = htsmsg_xml_get_cdata_str(device, "modelName")) == NULL)
952     goto finish;
953   if ((modelnum     = htsmsg_xml_get_cdata_str(device, "modelNumber")) == NULL)
954     modelnum = "";
955   if ((serialnum    = htsmsg_xml_get_cdata_str(device, "serialNumber")) == NULL)
956     serialnum = "";
957   if ((presentation = htsmsg_xml_get_cdata_str(device, "presentationURL")) == NULL)
958     presentation = "";
959   if ((udn          = htsmsg_xml_get_cdata_str(device, "UDN")) == NULL)
960     goto finish;
961   if ((tunercfg     = htsmsg_xml_get_cdata_str(device, "urn:ses-com:satipX_SATIPCAP")) == NULL)
962     tunercfg = "";
963 
964   uuid = NULL;
965   n = http_tokenize((char *)udn, argv, ARRAY_SIZE(argv), ':');
966   for (i = 0; i < n+1; i++)
967     if (argv[i] && strcmp(argv[i], "uuid") == 0) {
968       uuid = argv[++i];
969       break;
970     }
971   if (uuid == NULL || (d->uuid[0] && strcmp(uuid, d->uuid)))
972     goto finish;
973 
974   info.rtsp_port = 554;
975   info.srcs = 4;
976 
977   arg = http_arg_get(&hc->hc_args, "X-SATIP-RTSP-Port");
978   if (arg) {
979     i = atoi(arg);
980     if (i > 0 && i < 65535)
981       info.rtsp_port = i;
982   }
983   arg = http_arg_get(&hc->hc_args, "X-SATIP-Sources");
984   if (arg) {
985     i = atoi(arg);
986     if (i > 0 && i < 128)
987       info.srcs = i;
988   }
989 
990   info.myaddr = strdup(d->myaddr);
991   info.addr = strdup(d->url.host);
992   info.uuid = strdup(uuid);
993   info.bootid = strdup(d->bootid);
994   info.configid = strdup(d->configid);
995   info.deviceid = strdup(d->deviceid);
996   info.location = strdup(d->location);
997   info.server = strdup(d->server);
998   info.friendlyname = strdup(friendlyname);
999   info.manufacturer = strdup(manufacturer);
1000   info.manufacturerURL = strdup(manufacturerURL);
1001   info.modeldesc = strdup(modeldesc);
1002   info.modelname = strdup(modelname);
1003   info.modelnum = strdup(modelnum);
1004   info.serialnum = strdup(serialnum);
1005   info.presentation = strdup(presentation);
1006   info.tunercfg = strdup(tunercfg);
1007   htsmsg_destroy(xml);
1008   xml = NULL;
1009   pthread_mutex_lock(&global_lock);
1010   if (!satip_device_find(info.uuid))
1011     satip_device_create(&info);
1012   pthread_mutex_unlock(&global_lock);
1013   free(info.myaddr);
1014   free(info.location);
1015   free(info.server);
1016   free(info.addr);
1017   free(info.uuid);
1018   free(info.bootid);
1019   free(info.configid);
1020   free(info.deviceid);
1021   free(info.friendlyname);
1022   free(info.manufacturer);
1023   free(info.manufacturerURL);
1024   free(info.modeldesc);
1025   free(info.modelname);
1026   free(info.modelnum);
1027   free(info.serialnum);
1028   free(info.presentation);
1029   free(info.tunercfg);
1030 finish:
1031   htsmsg_destroy(xml);
1032 }
1033 
1034 static void
satip_discovery_timerq_cb(void * aux)1035 satip_discovery_timerq_cb(void *aux)
1036 {
1037   satip_discovery_t *d, *next;
1038   int r;
1039 
1040   lock_assert(&global_lock);
1041 
1042   next = TAILQ_FIRST(&satip_discoveries);
1043   while (next) {
1044     d = next;
1045     next = TAILQ_NEXT(d, disc_link);
1046     if (d->http_client) {
1047       if (mclk() - d->http_start > sec2mono(4))
1048         satip_discovery_destroy(d, 1);
1049       continue;
1050     }
1051 
1052     d->http_client = http_client_connect(d, HTTP_VERSION_1_1, d->url.scheme,
1053                                          d->url.host, d->url.port, NULL);
1054     if (d->http_client == NULL)
1055       satip_discovery_destroy(d, 1);
1056     else {
1057       d->http_start = mclk();
1058       d->http_client->hc_conn_closed = satip_discovery_http_closed;
1059       http_client_register(d->http_client);
1060       r = http_client_simple(d->http_client, &d->url);
1061       if (r < 0)
1062         satip_discovery_destroy(d, 1);
1063     }
1064   }
1065   if (TAILQ_FIRST(&satip_discoveries))
1066     mtimer_arm_rel(&satip_discovery_timerq, satip_discovery_timerq_cb, NULL, sec2mono(5));
1067 }
1068 
1069 static void
satip_discovery_service_received(uint8_t * data,size_t len,udp_connection_t * conn,struct sockaddr_storage * storage)1070 satip_discovery_service_received
1071   (uint8_t *data, size_t len, udp_connection_t *conn,
1072    struct sockaddr_storage *storage)
1073 {
1074   char *buf, *ptr, *saveptr;
1075   char *argv[10];
1076   char *st = NULL;
1077   char *location = NULL;
1078   char *server = NULL;
1079   char *uuid = NULL;
1080   char *bootid = NULL;
1081   char *configid = NULL;
1082   char *deviceid = NULL;
1083   char sockbuf[128];
1084   satip_discovery_t *d;
1085   int n, i;
1086 
1087   if (len > 8191 || atomic_get(&satip_discoveries_count) > 100)
1088     return;
1089   buf = alloca(len+1);
1090   memcpy(buf, data, len);
1091   buf[len] = '\0';
1092   ptr = strtok_r(buf, "\r\n", &saveptr);
1093   /* Request decoder */
1094   if (ptr) {
1095     if (http_tokenize(ptr, argv, 3, -1) != 3)
1096       return;
1097     if (conn->multicast) {
1098       if (strcmp(argv[0], "NOTIFY"))
1099         return;
1100       if (strcmp(argv[1], "*"))
1101         return;
1102       if (strcmp(argv[2], "HTTP/1.1"))
1103         return;
1104     } else {
1105       if (strcmp(argv[0], "HTTP/1.1"))
1106         return;
1107       if (strcmp(argv[1], "200"))
1108         return;
1109     }
1110     ptr = strtok_r(NULL, "\r\n", &saveptr);
1111   }
1112   /* Header decoder */
1113   while (1) {
1114     if (ptr == NULL)
1115       break;
1116     if (http_tokenize(ptr, argv, 2, ':') == 2) {
1117       if (strcmp(argv[0], "ST") == 0)
1118         st = argv[1];
1119       else if (strcmp(argv[0], "LOCATION") == 0)
1120         location = argv[1];
1121       else if (strcmp(argv[0], "SERVER") == 0)
1122         server = argv[1];
1123       else if (strcmp(argv[0], "BOOTID.UPNP.ORG") == 0)
1124         bootid = argv[1];
1125       else if (strcmp(argv[0], "CONFIGID.UPNP.ORG") == 0)
1126         configid = argv[1];
1127       else if (strcmp(argv[0], "DEVICEID.SES.COM") == 0)
1128         deviceid = argv[1];
1129       else if (strcmp(argv[0], "USN") == 0) {
1130         n = http_tokenize(argv[1], argv, ARRAY_SIZE(argv), ':');
1131         for (i = 0; i < n-1; i++)
1132           if (argv[i] && strcmp(argv[i], "uuid") == 0) {
1133             uuid = argv[++i];
1134             break;
1135           }
1136       }
1137     }
1138     ptr = strtok_r(NULL, "\r\n", &saveptr);
1139   }
1140   /* Sanity checks */
1141   if (st == NULL || strcmp(st, "urn:ses-com:device:SatIPServer:1"))
1142     goto add_uuid;
1143   if (uuid == NULL || strlen(uuid) < 16 || satip_server_match_uuid(uuid))
1144     goto add_uuid;
1145   if (location == NULL || strncmp(location, "http://", 7))
1146     goto add_uuid;
1147   if (server == NULL)
1148     goto add_uuid;
1149 
1150   /* Forward information to next layer */
1151 
1152   d = calloc(1, sizeof(satip_discovery_t));
1153   if (inet_ntop(conn->ip.ss_family, IP_IN_ADDR(conn->ip),
1154                 sockbuf, sizeof(sockbuf)) == NULL) {
1155     satip_discovery_destroy(d, 0);
1156     return;
1157   }
1158   d->myaddr   = strdup(sockbuf);
1159   d->location = strdup(location);
1160   d->server   = strdup(server);
1161   d->uuid     = strdup(uuid);
1162   d->bootid   = strdup(bootid ?: "");
1163   d->configid = strdup(configid ?: "");
1164   d->deviceid = strdup(deviceid ?: "");
1165   if (urlparse(d->location, &d->url)) {
1166     satip_discovery_destroy(d, 0);
1167     return;
1168   }
1169 
1170   pthread_mutex_lock(&global_lock);
1171   i = 1;
1172   if (!satip_discovery_find(d) && !satip_device_find(d->uuid)) {
1173     TAILQ_INSERT_TAIL(&satip_discoveries, d, disc_link);
1174     atomic_add(&satip_discoveries_count, 1);
1175     mtimer_arm_rel(&satip_discovery_timerq, satip_discovery_timerq_cb, NULL, ms2mono(250));
1176     i = 0;
1177   }
1178   pthread_mutex_unlock(&global_lock);
1179   if (i) /* duplicate */
1180     satip_discovery_destroy(d, 0);
1181   return;
1182 
1183 add_uuid:
1184   if (deviceid == NULL || uuid == NULL)
1185     return;
1186   /* if new uuid was discovered, retrigger MSEARCH */
1187   pthread_mutex_lock(&global_lock);
1188   if (!satip_device_find(uuid))
1189     mtimer_arm_rel(&satip_discovery_timer, satip_discovery_timer_cb, NULL, sec2mono(5));
1190   pthread_mutex_unlock(&global_lock);
1191 }
1192 
1193 static void
satip_discovery_static(const char * descurl)1194 satip_discovery_static(const char *descurl)
1195 {
1196   satip_discovery_t *d;
1197 
1198   lock_assert(&global_lock);
1199 
1200   if (satip_device_find_by_descurl(descurl))
1201     return;
1202   d = calloc(1, sizeof(satip_discovery_t));
1203   urlinit(&d->url);
1204   if (urlparse(descurl, &d->url)) {
1205     satip_discovery_destroy(d, 0);
1206     return;
1207   }
1208   d->myaddr   = strdup("");
1209   d->location = strdup(descurl);
1210   d->server   = strdup("");
1211   d->uuid     = strdup("");
1212   d->bootid   = strdup("");
1213   d->configid = strdup("");
1214   d->deviceid = strdup("");
1215   TAILQ_INSERT_TAIL(&satip_discoveries, d, disc_link);
1216   atomic_add(&satip_discoveries_count, 1);
1217   satip_discovery_timerq_cb(NULL);
1218 }
1219 
1220 static void
satip_discovery_service_destroy(upnp_service_t * us)1221 satip_discovery_service_destroy(upnp_service_t *us)
1222 {
1223   satip_discovery_service = NULL;
1224 }
1225 
1226 static void
satip_discovery_send_msearch(void * aux)1227 satip_discovery_send_msearch(void *aux)
1228 {
1229 #define MSG "\
1230 M-SEARCH * HTTP/1.1\r\n\
1231 HOST: 239.255.255.250:1900\r\n\
1232 MAN: \"ssdp:discover\"\r\n\
1233 MX: 2\r\n\
1234 ST: urn:ses-com:device:SatIPServer:1\r\n"
1235   int attempt = ((intptr_t)aux) % 10;
1236   htsbuf_queue_t q;
1237 
1238   /* UDP is not reliable - send this message three times */
1239   if (attempt < 1 || attempt > 3)
1240     return;
1241   if (satip_discovery_service == NULL)
1242     return;
1243 
1244   htsbuf_queue_init(&q, 0);
1245   htsbuf_append(&q, MSG, sizeof(MSG)-1);
1246   htsbuf_qprintf(&q, "USER-AGENT: unix/1.0 UPnP/1.1 TVHeadend/%s\r\n", tvheadend_version);
1247   htsbuf_append(&q, "\r\n", 2);
1248   upnp_send(&q, NULL, 0, 0);
1249   htsbuf_queue_flush(&q);
1250 
1251   mtimer_arm_rel(&satip_discovery_msearch_timer, satip_discovery_send_msearch,
1252                  (void *)(intptr_t)(attempt + 1), ms2mono(attempt * 11));
1253 #undef MSG
1254 }
1255 
1256 static void
satip_discovery_static_timer_cb(void * aux)1257 satip_discovery_static_timer_cb(void *aux)
1258 {
1259   static int next_timeout = 10;
1260   int i;
1261 
1262   if (!tvheadend_is_running())
1263     return;
1264   for (i = 0; i < satip_static_clients->num; i++)
1265     satip_discovery_static(satip_static_clients->str[i]);
1266   mtimer_arm_rel(&satip_discovery_static_timer, satip_discovery_static_timer_cb,
1267                  NULL, sec2mono(next_timeout));
1268   if (next_timeout < 3600)
1269     next_timeout = next_timeout >= 30 ? 3600 : 30;
1270 }
1271 
1272 static void
satip_discovery_timer_cb(void * aux)1273 satip_discovery_timer_cb(void *aux)
1274 {
1275   static int next_timeout = 10;
1276 
1277   if (!tvheadend_is_running())
1278     return;
1279   if (!atomic_get(&upnp_running)) {
1280     mtimer_arm_rel(&satip_discovery_timer, satip_discovery_timer_cb,
1281                    NULL, sec2mono(1));
1282     return;
1283   }
1284   if (satip_discovery_service == NULL) {
1285     satip_discovery_service              = upnp_service_create(upnp_service);
1286     if (satip_discovery_service) {
1287       satip_discovery_service->us_received = satip_discovery_service_received;
1288       satip_discovery_service->us_destroy  = satip_discovery_service_destroy;
1289     }
1290   }
1291   if (satip_discovery_service)
1292     satip_discovery_send_msearch((void *)1);
1293   mtimer_arm_rel(&satip_discovery_timer, satip_discovery_timer_cb,
1294                  NULL, sec2mono(next_timeout));
1295   if (next_timeout < 3600)
1296     next_timeout = next_timeout >= 30 ? 3600 : 30;
1297 }
1298 
1299 void
satip_device_discovery_start(void)1300 satip_device_discovery_start( void )
1301 {
1302   if (!satip_enabled)
1303     return;
1304   mtimer_arm_rel(&satip_discovery_timer, satip_discovery_timer_cb,
1305                  NULL, sec2mono(1));
1306   mtimer_arm_rel(&satip_discovery_static_timer, satip_discovery_static_timer_cb,
1307                  NULL, sec2mono(1));
1308 }
1309 
1310 /*
1311  * Initialization
1312  */
1313 
satip_init(int nosatip,str_list_t * clients)1314 void satip_init ( int nosatip, str_list_t *clients )
1315 {
1316   idclass_register(&satip_device_class);
1317 
1318   idclass_register(&satip_frontend_class);
1319   idclass_register(&satip_frontend_dvbt_class);
1320   idclass_register(&satip_frontend_dvbs_class);
1321   idclass_register(&satip_frontend_dvbs_slave_class);
1322   idclass_register(&satip_frontend_atsc_t_class);
1323   idclass_register(&satip_frontend_atsc_c_class);
1324 
1325   idclass_register(&satip_satconf_class);
1326 
1327   satip_enabled = !nosatip;
1328   TAILQ_INIT(&satip_discoveries);
1329   satip_static_clients = clients;
1330   if (satip_enabled) {
1331     dbus_register_rpc_str("satip_addr", NULL, satip_device_addr);
1332     satip_device_discovery_start();
1333   }
1334 }
1335 
satip_done(void)1336 void satip_done ( void )
1337 {
1338   tvh_hardware_t *th, *n;
1339   satip_discovery_t *d, *nd;
1340 
1341   pthread_mutex_lock(&global_lock);
1342   for (th = LIST_FIRST(&tvh_hardware); th != NULL; th = n) {
1343     n = LIST_NEXT(th, th_link);
1344     if (idnode_is_instance(&th->th_id, &satip_device_class)) {
1345       satip_device_destroy((satip_device_t *)th);
1346     }
1347   }
1348   for (d = TAILQ_FIRST(&satip_discoveries); d != NULL; d = nd) {
1349     nd = TAILQ_NEXT(d, disc_link);
1350     satip_discovery_destroy(d, 1);
1351   }
1352   pthread_mutex_unlock(&global_lock);
1353 }
1354