Ejemplo n.º 1
0
static void
handle_sigill(int x)
{
    /* Note that on some platforms, the SSL library tries */
    /* to determine the CPU capabilities with possible */
    /* unknown instructions */
    tvhwarn("CPU", "Illegal instruction handler (might be OK)");
    signal(SIGILL, handle_sigill);
}
Ejemplo n.º 2
0
static void
satip_device_hack( satip_device_t *sd )
{
  if (sd->sd_info.deviceid[0] &&
      strcmp(sd->sd_info.server, "Linux/1.0 UPnP/1.1 IDL4K/1.0") == 0) {
    /* AXE Linux distribution - Inverto firmware */
    /* version V1.13.0.105 and probably less */
    /* really ugly firmware - soooooo much restrictions */
    sd->sd_fullmux_ok  = 0;
    sd->sd_pids_max    = 32;
    sd->sd_pids_deladd = 0;
    tvhwarn("satip", "Detected old Inverto firmware V1.13.0.105 and less");
    tvhwarn("satip", "Upgrade to V1.16.0.120 - http://http://www.inverto.tv/support/ - IDL400s");
  } else if (strstr(sd->sd_info.location, ":8888/octonet.xml")) {
    /* OctopusNet requires pids in the SETUP RTSP command */
    sd->sd_pids0       = 1;
  } else if (strstr(sd->sd_info.manufacturer, "Triax") &&
             strstr(sd->sd_info.modelname, "TSS400")) {
    sd->sd_pilot_on    = 1;
  }
}
Ejemplo n.º 3
0
/**
 * Close the muxer and append trailer to output
 */
static int
lav_muxer_close(muxer_t *m)
{
  int ret = 0;
  lav_muxer_t *lm = (lav_muxer_t*)m;

  if(lm->lm_init && av_write_trailer(lm->lm_oc) < 0) {
    tvhwarn(LS_LIBAV,  "Failed to write %s trailer", 
	    muxer_container_type2txt(lm->m_config.m_type));
    lm->m_errors++;
    ret = -1;
  }
  return ret;
}
Ejemplo n.º 4
0
static void
epggrab_ota_done ( epggrab_ota_mux_t *om, int reason )
{
  static const char *reasons[] = {
    [EPGGRAB_OTA_DONE_COMPLETE]    = "complete",
    [EPGGRAB_OTA_DONE_TIMEOUT]     = "timeout",
    [EPGGRAB_OTA_DONE_NO_DATA]     = "no data",
    [EPGGRAB_OTA_DONE_STOLEN]      = "stolen"
  };
  char ubuf[UUID_HEX_SIZE];
  mpegts_mux_t *mm;
  epggrab_ota_map_t *map;

  if (om->om_save)
    epggrab_ota_save(om);

  mm = mpegts_mux_find0(&om->om_mux_uuid);
  if (mm == NULL) {
    tvhdebug(LS_EPGGRAB, "unable to find mux %s (grab done: %s)",
             uuid_get_hex(&om->om_mux_uuid, ubuf), reasons[reason]);
    return;
  }
  tvhdebug(LS_EPGGRAB, "grab done for %s (%s)", mm->mm_nicename, reasons[reason]);

  mtimer_disarm(&om->om_timer);
  mtimer_disarm(&om->om_data_timer);
  mtimer_disarm(&om->om_handlers_timer);

  assert(om->om_q_type == EPGGRAB_OTA_MUX_ACTIVE);
  TAILQ_REMOVE(&epggrab_ota_active, om, om_q_link);
  om->om_q_type = EPGGRAB_OTA_MUX_IDLE;
  LIST_FOREACH(map, &om->om_modules, om_link)
    if (map->om_module->stop)
      map->om_module->stop(map, mm);
  if (reason == EPGGRAB_OTA_DONE_STOLEN) {
    /* Do not requeue completed muxes */
    if (!om->om_done && om->om_requeue) {
      TAILQ_INSERT_HEAD(&epggrab_ota_pending, om, om_q_link);
      om->om_q_type = EPGGRAB_OTA_MUX_PENDING;
    } else {
      om->om_requeue = 0;
    }
  } else if (reason == EPGGRAB_OTA_DONE_TIMEOUT) {
    om->om_requeue = 0;
    LIST_FOREACH(map, &om->om_modules, om_link)
      if (!map->om_complete)
        tvhwarn(LS_EPGGRAB, "%s - data completion timeout for %s",
                map->om_module->name, mm->mm_nicename);
  } else {
Ejemplo n.º 5
0
udp_connection_t *
udp_sendinit ( int subsystem, const char *name,
               const char *ifname, int txsize )
{
  int fd, ifindex;
  udp_connection_t *uc;

  uc = calloc(1, sizeof(udp_connection_t));
  uc->fd                   = -1;
  uc->ifname               = ifname ? strdup(ifname) : NULL;
  uc->subsystem            = subsystem;
  uc->name                 = name ? strdup(name) : NULL;
  uc->rxtxsize             = txsize;

  /* Open socket */
  if ((fd = tvh_socket(uc->ip.ss_family, SOCK_DGRAM, 0)) == -1) {
    tvherror(subsystem, "%s - failed to create socket [%s]",
             name, strerror(errno));
    udp_close(uc);
    return UDP_FATAL_ERROR;
  }

  uc->fd = fd;

  /* Bind to interface */
  ifindex = udp_ifindex_required(uc) ? udp_get_ifindex(ifname) : 0;
  if (ifindex < 0) {
    tvherror(subsystem, "%s - could not find interface %s",
             name, ifname);
    goto error;
  }

  if (uc->multicast) {
    if (uc->ip.ss_family == AF_INET) {
#if !defined(PLATFORM_DARWIN)
      struct ip_mreqn m;
      memset(&m, 0, sizeof(m));
      m.imr_ifindex = ifindex;
#else
      struct in_addr m;
      if (udp_get_ifaddr(fd, ifname, &m) == -1) {
        tvherror(subsystem, "%s - cannot find ip address for interface %s [e=%s]",
                 name, ifname,  strerror(errno));
        goto error;
      }
#endif
      if (setsockopt(fd, udp_get_solip(), IP_MULTICAST_IF, &m, sizeof(m)))
        tvhwarn(subsystem, "%s - cannot set source interface %s [%s]",
                name, ifname, strerror(errno));
    } else {
      struct ipv6_mreq m;
      memset(&m,   0, sizeof(m));
      m.ipv6mr_interface = ifindex;
#ifdef SOL_IPV6
      if (setsockopt(fd, SOL_IPV6, IPV6_MULTICAST_IF, &m, sizeof(m))) {
        tvhwarn(subsystem, "%s - cannot set source interface %s [%s]",
                name, ifname, strerror(errno));
      }
#else
      tvherror(subsystem, "IPv6 multicast not supported");
      goto error;
#endif
    }
  }

  /* Increase TX buffer size */
  if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &txsize, sizeof(txsize)) == -1)
    tvhwarn(subsystem, "%s - cannot increase UDP tx buffer size [%s]",
            name, strerror(errno));

  return uc;

error:
  udp_close(uc);
  return NULL;
}
Ejemplo n.º 6
0
udp_connection_t *
udp_bind ( int subsystem, const char *name,
           const char *bindaddr, int port, const char *multicast_src,
           const char *ifname, int rxsize, int txsize )
{
  int fd, ifindex, reuse = 1;
  udp_connection_t *uc;
  char buf[256];
  socklen_t addrlen;

  uc = calloc(1, sizeof(udp_connection_t));
  uc->fd                   = -1;
  uc->host                 = bindaddr ? strdup(bindaddr) : NULL;
  uc->port                 = port;
  uc->ifname               = ifname ? strdup(ifname) : NULL;
  uc->subsystem            = subsystem;
  uc->name                 = name ? strdup(name) : NULL;
  uc->rxtxsize             = rxsize;

  if (udp_resolve(uc, &uc->ip, uc->host, port, &uc->multicast, 1)) {
    udp_close(uc);
    return UDP_FATAL_ERROR;
  }

  /* Open socket */
  if ((fd = tvh_socket(uc->ip.ss_family, SOCK_DGRAM, 0)) == -1) {
    tvherror(subsystem, "%s - failed to create socket [%s]",
             name, strerror(errno));
    udp_close(uc);
    return UDP_FATAL_ERROR;
  }

  uc->fd = fd;

  /* Mark reuse address */
  if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse))) {
    tvherror(subsystem, "%s - failed to reuse address for socket [%s]",
             name, strerror(errno));
    udp_close(uc);
    return UDP_FATAL_ERROR;
  }

  /* Bind to interface */
  ifindex = udp_ifindex_required(uc) ? udp_get_ifindex(ifname) : 0;
  if (ifindex < 0) {
    tvherror(subsystem, "%s - could not find interface %s",
             name, ifname);
    goto error;
  }

  /* IPv4 */
  if (uc->ip.ss_family == AF_INET) {
    /* Bind */
    if (bind(fd, (struct sockaddr *)&uc->ip, sizeof(struct sockaddr_in))) {
      inet_ntop(AF_INET, &IP_AS_V4(uc->ip, addr), buf, sizeof(buf));
      tvherror(subsystem, "%s - cannot bind %s:%hu [e=%s]",
               name, buf, ntohs(IP_AS_V4(uc->ip, port)), strerror(errno));
      goto error;
    }

    if (uc->multicast) {
      /* Join multicast group */
      if (multicast_src && *multicast_src) {
        /* Join with specific source address (SSM) */
        struct ip_mreq_source ms;
        memset(&ms, 0, sizeof(ms));

        ms.imr_multiaddr = IP_AS_V4(uc->ip, addr);

        /* Note, ip_mreq_source does not support the ifindex parameter,
           so we have to resolve to the ip of the interface on all platforms. */
        if (udp_get_ifaddr(fd, ifname, &ms.imr_interface) == -1) {
          tvherror(subsystem, "%s - cannot find ip address for interface %s [e=%s]",
                   name, ifname, strerror(errno));
          goto error;
        }

        if (inet_pton(AF_INET, multicast_src, &ms.imr_sourceaddr) < 1) {
          tvherror(subsystem, "%s - invalid ipv4 address '%s' specified as multicast source [e=%s]",
                   name, multicast_src, strerror(errno));
          goto error;
        }

        if (setsockopt(fd, udp_get_solip(), IP_ADD_SOURCE_MEMBERSHIP,
                       &ms, sizeof(ms)) < 0) {
          tvherror(subsystem, "%s - setsockopt IP_ADD_SOURCE_MEMBERSHIP failed [e=%s]",
                   name,  strerror(errno));
          goto error;
        }
      }
      else {
        /* Standard multicast join (non-SSM) */
#if defined(PLATFORM_DARWIN)
        struct ip_mreq       m;
#else
        struct ip_mreqn      m;
#endif
        memset(&m,   0, sizeof(m));

        m.imr_multiaddr      = IP_AS_V4(uc->ip, addr);
#if !defined(PLATFORM_DARWIN)
        m.imr_address.s_addr = 0;
        m.imr_ifindex        = ifindex;
#else
        if (udp_get_ifaddr(fd, ifname, &m.imr_interface) == -1) {
          tvherror(subsystem, "%s - cannot find ip address for interface %s [e=%s]",
                   name, ifname,  strerror(errno));
          goto error;
        }
#endif

        if (setsockopt(fd, udp_get_solip(), IP_ADD_MEMBERSHIP, &m, sizeof(m))) {
          inet_ntop(AF_INET, &m.imr_multiaddr, buf, sizeof(buf));
          tvhwarn(subsystem, "%s - cannot join %s [%s]",
                  name, buf, strerror(errno));
        }
      }
   }

  /* Bind to IPv6 group */
  } else {
    struct ipv6_mreq m;
    memset(&m,   0, sizeof(m));

    /* Bind */
    if (bind(fd, (struct sockaddr *)&uc->ip, sizeof(struct sockaddr_in6))) {
      inet_ntop(AF_INET6, &IP_AS_V6(uc->ip, addr), buf, sizeof(buf));
      tvherror(subsystem, "%s - cannot bind %s:%hu [e=%s]",
               name, buf, ntohs(IP_AS_V6(uc->ip, port)), strerror(errno));
      goto error;
    }

    if (uc->multicast) {
      /* Join group */
      m.ipv6mr_multiaddr = IP_AS_V6(uc->ip, addr);
      m.ipv6mr_interface = ifindex;
#ifdef SOL_IPV6
      if (setsockopt(fd, SOL_IPV6, IPV6_ADD_MEMBERSHIP, &m, sizeof(m))) {
        inet_ntop(AF_INET, &m.ipv6mr_multiaddr, buf, sizeof(buf));
        tvhwarn(subsystem, "%s - cannot join %s [%s]",
                name, buf, strerror(errno));
      }
#else
      tvherror(subsystem, "IPv6 multicast not supported");
      goto error;
#endif
    }
  }

  addrlen = sizeof(uc->ip);
  if (getsockname(fd, (struct sockaddr *)&uc->ip, &addrlen)) {
    tvherror(subsystem, "%s - cannot obtain socket name [%s]",
             name, strerror(errno));
    goto error;
  }
    
  /* Increase/Decrease RX buffer size */
  if (rxsize > 0 &&
      setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rxsize, sizeof(rxsize)) == -1)
    tvhwarn(subsystem, "%s - cannot change UDP rx buffer size [%s]",
            name, strerror(errno));

  /* Increase/Decrease TX buffer size */
  if (txsize > 0 &&
      setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &txsize, sizeof(txsize)) == -1)
    tvhwarn(subsystem, "%s - cannot change UDP tx buffer size [%s]",
            name, strerror(errno));

  return uc;

error:
  udp_close(uc);
  return NULL;
}
Ejemplo n.º 7
0
int
main(int argc, char **argv)
{
  int i;
  sigset_t set;
#if ENABLE_MPEGTS
  uint32_t adapter_mask = 0;
#endif
  int  log_level   = LOG_INFO;
  int  log_options = TVHLOG_OPT_MILLIS | TVHLOG_OPT_STDERR | TVHLOG_OPT_SYSLOG;
  const char *log_debug = NULL, *log_trace = NULL;
  gid_t gid = -1;
  uid_t uid = -1;
  char buf[512];
  FILE *pidfile = NULL;
  extern int dvb_bouquets_parse;

  main_tid = pthread_self();

  /* Setup global mutexes */
  pthread_mutex_init(&fork_lock, NULL);
  pthread_mutex_init(&global_lock, NULL);
  pthread_mutex_init(&tasklet_lock, NULL);
  pthread_mutex_init(&atomic_lock, NULL);
  pthread_cond_init(&gtimer_cond, NULL);
  pthread_cond_init(&tasklet_cond, NULL);
  TAILQ_INIT(&tasklets);

  /* Defaults */
  tvheadend_webui_port      = 9981;
  tvheadend_webroot         = NULL;
  tvheadend_htsp_port       = 9982;
  tvheadend_htsp_port_extra = 0;
  time(&dispatch_clock);

  /* Command line options */
  int         opt_help         = 0,
              opt_version      = 0,
              opt_fork         = 0,
              opt_firstrun     = 0,
              opt_stderr       = 0,
              opt_syslog       = 0,
              opt_nosyslog     = 0,
              opt_uidebug      = 0,
              opt_abort        = 0,
              opt_noacl        = 0,
              opt_fileline     = 0,
              opt_threadid     = 0,
              opt_libav        = 0,
              opt_ipv6         = 0,
              opt_satip_rtsp   = 0,
#if ENABLE_TSFILE
              opt_tsfile_tuner = 0,
#endif
              opt_dump         = 0,
              opt_xspf         = 0,
              opt_dbus         = 0,
              opt_dbus_session = 0,
              opt_nobackup     = 0,
              opt_nobat        = 0;
  const char *opt_config       = NULL,
             *opt_user         = NULL,
             *opt_group        = NULL,
             *opt_logpath      = NULL,
             *opt_log_debug    = NULL,
             *opt_log_trace    = NULL,
             *opt_pidpath      = "/var/run/tvheadend.pid",
#if ENABLE_LINUXDVB
             *opt_dvb_adapters = NULL,
#endif
             *opt_bindaddr     = NULL,
             *opt_subscribe    = NULL,
             *opt_user_agent   = NULL;
  str_list_t  opt_satip_xml    = { .max = 10, .num = 0, .str = calloc(10, sizeof(char*)) };
  str_list_t  opt_tsfile       = { .max = 10, .num = 0, .str = calloc(10, sizeof(char*)) };
  cmdline_opt_t cmdline_opts[] = {
    {   0, NULL,        N_("Generic Options"),         OPT_BOOL, NULL         },
    { 'h', "help",      N_("Show this page"),          OPT_BOOL, &opt_help    },
    { 'v', "version",   N_("Show version information"),OPT_BOOL, &opt_version },

    {   0, NULL,        N_("Service Configuration"),   OPT_BOOL, NULL         },
    { 'c', "config",    N_("Alternate config path"),   OPT_STR,  &opt_config  },
    { 'B', "nobackup",  N_("Don't backup config tree at upgrade"), OPT_BOOL, &opt_nobackup },
    { 'f', "fork",      N_("Fork and run as daemon"),  OPT_BOOL, &opt_fork    },
    { 'u', "user",      N_("Run as user"),             OPT_STR,  &opt_user    },
    { 'g', "group",     N_("Run as group"),            OPT_STR,  &opt_group   },
    { 'p', "pid",       N_("Alternate pid path"),      OPT_STR,  &opt_pidpath },
    { 'C', "firstrun",  N_("If no user account exists then create one with\n"
	                   "no username and no password. Use with care as\n"
	                   "it will allow world-wide administrative access\n"
	                   "to your Tvheadend installation until you edit/create\n"
	                   "access-control from within the Tvheadend UI"),
      OPT_BOOL, &opt_firstrun },
#if ENABLE_DBUS_1
    { 'U', "dbus",      N_("Enable DBus"),
      OPT_BOOL, &opt_dbus },
    { 'e', "dbus_session", N_("DBus - use the session message bus instead system one"),
      OPT_BOOL, &opt_dbus_session },
#endif
#if ENABLE_LINUXDVB
    { 'a', "adapters",  N_("Only use specified DVB adapters (comma separated)"),
      OPT_STR, &opt_dvb_adapters },
#endif
#if ENABLE_SATIP_SERVER
    {   0, "satip_rtsp", N_("SAT>IP RTSP port number for server\n"
                            "(default: -1 = disable, 0 = webconfig, standard port is 554)"),
      OPT_INT, &opt_satip_rtsp },
#endif
#if ENABLE_SATIP_CLIENT
    {   0, "satip_xml", N_("URL with the SAT>IP server XML location"),
      OPT_STR_LIST, &opt_satip_xml },
#endif
    {   0, NULL,         N_("Server Connectivity"),    OPT_BOOL, NULL         },
    { '6', "ipv6",       N_("Listen on IPv6"),         OPT_BOOL, &opt_ipv6    },
    { 'b', "bindaddr",   N_("Specify bind address"),   OPT_STR,  &opt_bindaddr},
    {   0, "http_port",  N_("Specify alternative http port"),
      OPT_INT, &tvheadend_webui_port },
    {   0, "http_root",  N_("Specify alternative http webroot"),
      OPT_STR, &tvheadend_webroot },
    {   0, "htsp_port",  N_("Specify alternative htsp port"),
      OPT_INT, &tvheadend_htsp_port },
    {   0, "htsp_port2", N_("Specify extra htsp port"),
      OPT_INT, &tvheadend_htsp_port_extra },
    {   0, "useragent",  N_("Specify User-Agent header for the http client"),
      OPT_STR, &opt_user_agent },
    {   0, "xspf",       N_("Use XSPF playlist instead of M3U"),
      OPT_BOOL, &opt_xspf },

    {   0, NULL,        N_("Debug Options"),           OPT_BOOL, NULL         },
    { 'd', "stderr",    N_("Enable debug on stderr"),  OPT_BOOL, &opt_stderr  },
    { 's', "syslog",    N_("Enable debug to syslog"),  OPT_BOOL, &opt_syslog  },
    { 'S', "nosyslog",  N_("Disable syslog (all msgs)"), OPT_BOOL, &opt_nosyslog },
    { 'l', "logfile",   N_("Enable debug to file"),    OPT_STR,  &opt_logpath },
    {   0, "debug",     N_("Enable debug subsystems"),  OPT_STR,  &opt_log_debug },
#if ENABLE_TRACE
    {   0, "trace",     N_("Enable trace subsystems"), OPT_STR,  &opt_log_trace },
#endif
    {   0, "fileline",  N_("Add file and line numbers to debug"), OPT_BOOL, &opt_fileline },
    {   0, "threadid",  N_("Add the thread ID to debug"), OPT_BOOL, &opt_threadid },
#if ENABLE_LIBAV
    {   0, "libav",     N_("More verbose libav log"),  OPT_BOOL, &opt_libav },
#endif
    {   0, "uidebug",   N_("Enable webUI debug (non-minified JS)"), OPT_BOOL, &opt_uidebug },
    { 'A', "abort",     N_("Immediately abort"),       OPT_BOOL, &opt_abort   },
    { 'D', "dump",      N_("Enable coredumps for daemon"), OPT_BOOL, &opt_dump },
    {   0, "noacl",     N_("Disable all access control checks"),
      OPT_BOOL, &opt_noacl },
    {   0, "nobat",     N_("Disable DVB bouquets"),
      OPT_BOOL, &opt_nobat },
    { 'j', "join",      N_("Subscribe to a service permanently"),
      OPT_STR, &opt_subscribe },


#if ENABLE_TSFILE || ENABLE_TSDEBUG
    { 0, NULL, N_("Testing options"), OPT_BOOL, NULL },
    { 0, "tsfile_tuners", N_("Number of tsfile tuners"), OPT_INT, &opt_tsfile_tuner },
    { 0, "tsfile", N_("tsfile input (mux file)"), OPT_STR_LIST, &opt_tsfile },
#endif
#if ENABLE_TSDEBUG
    { 0, "tsdebug", N_("Output directory for tsdebug"), OPT_STR, &tvheadend_tsdebug },
#endif

  };

  /* Get current directory */
  tvheadend_cwd0 = dirname(tvh_strdupa(argv[0]));
  tvheadend_cwd = dirname(tvh_strdupa(tvheadend_cwd0));

  /* Set locale */
  setlocale(LC_ALL, "");
  setlocale(LC_NUMERIC, "C");

  /* make sure the timezone is set */
  tzset();

  /* Process command line */
  for (i = 1; i < argc; i++) {

    /* Find option */
    cmdline_opt_t *opt
      = cmdline_opt_find(cmdline_opts, ARRAY_SIZE(cmdline_opts), argv[i]);
    if (!opt)
      show_usage(argv[0], cmdline_opts, ARRAY_SIZE(cmdline_opts),
                 _("invalid option specified [%s]"), argv[i]);

    /* Process */
    if (opt->type == OPT_BOOL)
      *((int*)opt->param) = 1;
    else if (++i == argc)
      show_usage(argv[0], cmdline_opts, ARRAY_SIZE(cmdline_opts),
                 _("option %s requires a value"), opt->lopt);
    else if (opt->type == OPT_INT)
      *((int*)opt->param) = atoi(argv[i]);
    else if (opt->type == OPT_STR_LIST) {
      str_list_t *strl = opt->param;
      if (strl->num < strl->max)
        strl->str[strl->num++] = argv[i];
    }
    else
      *((char**)opt->param) = argv[i];

    /* Stop processing */
    if (opt_help)
      show_usage(argv[0], cmdline_opts, ARRAY_SIZE(cmdline_opts), NULL);
    if (opt_version)
      show_version(argv[0]);
  }

  /* Additional cmdline processing */
  if (opt_nobat)
    dvb_bouquets_parse = 0;
#if ENABLE_LINUXDVB
  if (!opt_dvb_adapters) {
    adapter_mask = ~0;
  } else {
    char *p, *e;
    char *r = NULL;
    char *dvb_adapters = strdup(opt_dvb_adapters);
    adapter_mask = 0x0;
    p = strtok_r(dvb_adapters, ",", &r);
    while (p) {
      int a = strtol(p, &e, 10);
      if (*e != 0 || a < 0 || a > 31) {
        fprintf(stderr, _("Invalid adapter number '%s'\n"), p);
        free(dvb_adapters);
        return 1;
      }
      adapter_mask |= (1 << a);
      p = strtok_r(NULL, ",", &r);
    }
    free(dvb_adapters);
    if (!adapter_mask) {
      fprintf(stderr, "%s", _("No adapters specified!\n"));
      return 1;
    }
  }
#endif
  if (tvheadend_webroot) {
    char *tmp;
    if (*tvheadend_webroot == '/')
      tmp = strdup(tvheadend_webroot);
    else {
      tmp = malloc(strlen(tvheadend_webroot)+2);
      *tmp = '/';
      strcpy(tmp+1, tvheadend_webroot);
    }
    if (tmp[strlen(tmp)-1] == '/')
      tmp[strlen(tmp)-1] = '\0';
    tvheadend_webroot = tmp;
  }
  tvheadend_webui_debug = opt_uidebug;

  /* Setup logging */
  if (isatty(2))
    log_options |= TVHLOG_OPT_DECORATE;
  if (opt_stderr || opt_syslog || opt_logpath) {
    if (!opt_log_trace && !opt_log_debug)
      log_debug      = "all";
    log_level      = LOG_DEBUG;
    if (opt_stderr)
      log_options   |= TVHLOG_OPT_DBG_STDERR;
    if (opt_syslog)
      log_options   |= TVHLOG_OPT_DBG_SYSLOG;
    if (opt_logpath)
      log_options   |= TVHLOG_OPT_DBG_FILE;
  }
  if (opt_nosyslog)
    log_options &= ~(TVHLOG_OPT_SYSLOG|TVHLOG_OPT_DBG_SYSLOG);
  if (opt_fileline)
    log_options |= TVHLOG_OPT_FILELINE;
  if (opt_threadid)
    log_options |= TVHLOG_OPT_THREAD;
  if (opt_libav)
    log_options |= TVHLOG_OPT_LIBAV;
  if (opt_log_trace) {
    log_level  = LOG_TRACE;
    log_trace  = opt_log_trace;
  }
  if (opt_log_debug)
    log_debug  = opt_log_debug;
    
  tvhlog_init(log_level, log_options, opt_logpath);
  tvhlog_set_debug(log_debug);
  tvhlog_set_trace(log_trace);
  tvhinfo("main", "Log started");
 
  signal(SIGPIPE, handle_sigpipe); // will be redundant later
  signal(SIGILL, handle_sigill);   // see handler..

  /* Set priviledges */
  if(opt_fork || opt_group || opt_user) {
    const char *homedir;
    struct group  *grp = getgrnam(opt_group ?: "video");
    struct passwd *pw  = opt_user ? getpwnam(opt_user) : NULL;

    if(grp != NULL) {
      gid = grp->gr_gid;
    } else {
      gid = 1;
    }

    if (pw != NULL) {
      if (getuid() != pw->pw_uid) {
        gid_t glist[16];
        int gnum;
        gnum = get_user_groups(pw, glist, ARRAY_SIZE(glist));
        if (gnum > 0 && setgroups(gnum, glist)) {
          char buf[256] = "";
          int i;
          for (i = 0; i < gnum; i++)
            snprintf(buf + strlen(buf), sizeof(buf) - 1 - strlen(buf),
                     ",%d", glist[i]);
          tvhlog(LOG_ALERT, "START",
                 "setgroups(%s) failed, do you have permission?", buf+1);
          return 1;
        }
      }
      uid     = pw->pw_uid;
      homedir = pw->pw_dir;
      setenv("HOME", homedir, 1);
    } else {
      uid = 1;
    }
  }

  uuid_init();
  config_boot(opt_config, gid, uid);
  tcp_server_preinit(opt_ipv6);
  http_server_init(opt_bindaddr);    // bind to ports only
  htsp_init(opt_bindaddr);	     // bind to ports only
  satip_server_init(opt_satip_rtsp); // bind to ports only

  if (opt_fork)
    pidfile = tvh_fopen(opt_pidpath, "w+");

  if (gid != -1 && (getgid() != gid) && setgid(gid)) {
    tvhlog(LOG_ALERT, "START",
           "setgid(%d) failed, do you have permission?", gid);
    return 1;
  }
  if (uid != -1 && (getuid() != uid) && setuid(uid)) {
    tvhlog(LOG_ALERT, "START",
           "setuid(%d) failed, do you have permission?", uid);
    return 1;
  }

  /* Daemonise */
  if(opt_fork) {
    if(daemon(0, 0)) {
      exit(2);
    }
    if(pidfile != NULL) {
      fprintf(pidfile, "%d\n", getpid());
      fclose(pidfile);
    }

    /* Make dumpable */
    if (opt_dump) {
#ifdef PLATFORM_LINUX
      if (chdir("/tmp"))
        tvhwarn("START", "failed to change cwd to /tmp");
      prctl(PR_SET_DUMPABLE, 1);
#else
      tvhwarn("START", "Coredumps not implemented on your platform");
#endif
    }

    umask(0);
  }

  tvheadend_running = 1;

  /* Start log thread (must be done post fork) */
  tvhlog_start();

  /* Alter logging */
  if (opt_fork)
    tvhlog_options &= ~TVHLOG_OPT_STDERR;
  if (!isatty(2))
    tvhlog_options &= ~TVHLOG_OPT_DECORATE;
  
  /* Initialise clock */
  pthread_mutex_lock(&global_lock);
  time(&dispatch_clock);

  /* Signal handling */
  sigfillset(&set);
  sigprocmask(SIG_BLOCK, &set, NULL);
  trap_init(argv[0]);

  /* SSL library init */
  OPENSSL_config(NULL);
  SSL_load_error_strings();
  SSL_library_init();

  /* Initialise configuration */
  notify_init();
  idnode_init();
  spawn_init();
  config_init(opt_nobackup == 0);

  /**
   * Initialize subsystems
   */

  epg_in_load = 1;

  tvhthread_create(&tasklet_tid, NULL, tasklet_thread, NULL);

  dbus_server_init(opt_dbus, opt_dbus_session);

  intlconv_init();
  
  api_init();

  fsmonitor_init();

  libav_init();

  tvhtime_init();

  profile_init();

  imagecache_init();

  http_client_init(opt_user_agent);
  esfilter_init();

  bouquet_init();

  service_init();

  dvb_init();

#if ENABLE_MPEGTS
  mpegts_init(adapter_mask, &opt_satip_xml, &opt_tsfile, opt_tsfile_tuner);
#endif

  channel_init();

  bouquet_service_resolve();

  subscription_init();

  dvr_config_init();

  access_init(opt_firstrun, opt_noacl);

#if ENABLE_TIMESHIFT
  timeshift_init();
#endif

  tcp_server_init();
  webui_init(opt_xspf);
#if ENABLE_UPNP
  upnp_server_init(opt_bindaddr);
#endif

  service_mapper_init();

  descrambler_init();

  epggrab_init();
  epg_init();

  dvr_init();

  dbus_server_start();

  http_server_register();
  satip_server_register();
  htsp_register();

  if(opt_subscribe != NULL)
    subscription_dummy_join(opt_subscribe, 1);

  avahi_init();
  bonjour_init();

  epg_updated(); // cleanup now all prev ref's should have been created
  epg_in_load = 0;

  pthread_mutex_unlock(&global_lock);

  /**
   * Wait for SIGTERM / SIGINT, but only in this thread
   */

  sigemptyset(&set);
  sigaddset(&set, SIGTERM);
  sigaddset(&set, SIGINT);

  signal(SIGTERM, doexit);
  signal(SIGINT, doexit);

  pthread_sigmask(SIG_UNBLOCK, &set, NULL);

  tvhlog(LOG_NOTICE, "START", "HTS Tvheadend version %s started, "
         "running as PID:%d UID:%d GID:%d, CWD:%s CNF:%s",
         tvheadend_version,
         getpid(), getuid(), getgid(), getcwd(buf, sizeof(buf)),
         hts_settings_get_root());

  if(opt_abort)
    abort();

  mainloop();

#if ENABLE_DBUS_1
  tvhftrace("main", dbus_server_done);
#endif
#if ENABLE_UPNP
  tvhftrace("main", upnp_server_done);
#endif
  tvhftrace("main", satip_server_done);
  tvhftrace("main", htsp_done);
  tvhftrace("main", http_server_done);
  tvhftrace("main", webui_done);
  tvhftrace("main", fsmonitor_done);
  tvhftrace("main", http_client_done);
  tvhftrace("main", tcp_server_done);

  // Note: the locking is obviously a bit redundant, but without
  //       we need to disable the gtimer_arm call in epg_save()
  pthread_mutex_lock(&global_lock);
  tvhftrace("main", epg_save);

#if ENABLE_TIMESHIFT
  tvhftrace("main", timeshift_term);
#endif
  pthread_mutex_unlock(&global_lock);

  tvhftrace("main", epggrab_done);
#if ENABLE_MPEGTS
  tvhftrace("main", mpegts_done);
#endif
  tvhftrace("main", descrambler_done);
  tvhftrace("main", service_mapper_done);
  tvhftrace("main", service_done);
  tvhftrace("main", channel_done);
  tvhftrace("main", bouquet_done);
  tvhftrace("main", dvr_done);
  tvhftrace("main", subscription_done);
  tvhftrace("main", access_done);
  tvhftrace("main", epg_done);
  tvhftrace("main", avahi_done);
  tvhftrace("main", bonjour_done);
  tvhftrace("main", imagecache_done);
  tvhftrace("main", lang_code_done);
  tvhftrace("main", api_done);

  tvhtrace("main", "tasklet enter");
  pthread_cond_signal(&tasklet_cond);
  pthread_join(tasklet_tid, NULL);
  tvhtrace("main", "tasklet thread end");
  tasklet_flush();
  tvhtrace("main", "tasklet leave");

  tvhftrace("main", hts_settings_done);
  tvhftrace("main", dvb_done);
  tvhftrace("main", lang_str_done);
  tvhftrace("main", esfilter_done);
  tvhftrace("main", profile_done);
  tvhftrace("main", intlconv_done);
  tvhftrace("main", urlparse_done);
  tvhftrace("main", idnode_done);
  tvhftrace("main", notify_done);
  tvhftrace("main", spawn_done);

  tvhlog(LOG_NOTICE, "STOP", "Exiting HTS Tvheadend");
  tvhlog_end();

  tvhftrace("main", config_done);

  if(opt_fork)
    unlink(opt_pidpath);
    
#if ENABLE_TSFILE
  free(opt_tsfile.str);
#endif
  free(opt_satip_xml.str);

  /* OpenSSL - welcome to the "cleanup" hell */
  ENGINE_cleanup();
  RAND_cleanup();
  CRYPTO_cleanup_all_ex_data();
  EVP_cleanup();
  CONF_modules_free();
#ifndef OPENSSL_NO_COMP
  COMP_zlib_cleanup();
#endif
  ERR_remove_state(0);
  ERR_free_strings();
#ifndef OPENSSL_NO_COMP
  sk_SSL_COMP_free(SSL_COMP_get_compression_methods());
#endif
  /* end of OpenSSL cleanup code */

#if ENABLE_DBUS_1
  extern void dbus_shutdown(void);
  if (opt_dbus) dbus_shutdown();
#endif
  return 0;
}

/**
 *
 */
void
tvh_str_set(char **strp, const char *src)
{
  free(*strp);
  *strp = src ? strdup(src) : NULL;
}


/**
 *
 */
int
tvh_str_update(char **strp, const char *src)
{
  if(src == NULL)
    return 0;
  free(*strp);
  *strp = strdup(src);
  return 1;
}


/**
 *
 */
void
scopedunlock(pthread_mutex_t **mtxp)
{
  pthread_mutex_unlock(*mtxp);
}
Ejemplo n.º 8
0
int
rtsp_setup_decode( http_client_t *hc, int satip )
{
  char *argv[32], *argv2[2], *p;
  int i, n, j;

#if 0
  { http_arg_t *ra;
  TAILQ_FOREACH(ra, &hc->hc_args, link)
    printf("  %s: %s\n", ra->key, ra->val); }
#endif
  rtsp_clear_session(hc);
  if (hc->hc_code != 200)
    return -EIO;
  p = http_arg_get(&hc->hc_args, "Session");
  if (p == NULL)
    return -EIO;
  n = http_tokenize(p, argv, 32, ';');
  if (n < 1)
    return -EIO;
  hc->hc_rtsp_session = strdup(argv[0]);
  for (i = 1; i < n; i++) {
    if (strncasecmp(argv[i], "timeout=", 8) == 0) {
      hc->hc_rtp_timeout = atoi(argv[i] + 8);
      if (hc->hc_rtp_timeout < 20 || hc->hc_rtp_timeout > 3600) {
        tvhwarn(LS_RTSP, "timeout value out of range 20-3600 (%i)", hc->hc_rtp_timeout);
        return -EIO;
      }
    }
  }
  if (satip) {
    p = http_arg_get(&hc->hc_args, "com.ses.streamID");
    if (p == NULL)
      return -EIO;
    /* zero is valid stream id per specification */
    while (*p && ((*p == '0' && *(p + 1) == '0') || *p < ' '))
      p++;
    if (p[0] == '0' && p[1] == '\0') {
      hc->hc_rtsp_stream_id = 0;
    } else {
      hc->hc_rtsp_stream_id = atoll(p);
      if (hc->hc_rtsp_stream_id <= 0)
        return -EIO;
    }
  }
  p = http_arg_get(&hc->hc_args, "Transport");
  if (p == NULL)
    return -EIO;
  n = http_tokenize(p, argv, 32, ';');
  if (n < 2)
    return -EIO;
  hc->hc_rtp_tcp = -1;
  hc->hc_rtcp_tcp = -1;
  hc->hc_rtp_port = -1;
  hc->hc_rtcp_port = -1;
  if (!strcasecmp(argv[0], "RTP/AVP/TCP")) {
    for (i = 1; i < n; i++) {
      if (strncmp(argv[i], "interleaved=", 12) == 0) {
        j = http_tokenize(argv[i] + 12, argv2, 2, '-');
        if (j > 0) {
          hc->hc_rtp_tcp = atoi(argv2[0]);
          if (hc->hc_rtp_tcp < 0)
            return -EIO;
          if (j > 1) {
            hc->hc_rtcp_tcp = atoi(argv2[1]);
            if (hc->hc_rtcp_tcp < 0)
              return -EIO;
          }
        } else {
          return -EIO;
        }
      }
    }
  } else if (!strcasecmp(argv[0], "RTP/AVP") ||
             !strcasecmp(argv[0], "RTP/AVP/UDP")) {
    if (n < 3)
      return -EIO;
    hc->hc_rtp_multicast = strcasecmp(argv[1], "multicast") == 0;
    if (strcasecmp(argv[1], "unicast") && !hc->hc_rtp_multicast)
      return -EIO;
    for (i = 2; i < n; i++) {
      if (strncmp(argv[i], "destination=", 12) == 0)
        hc->hc_rtp_dest = strdup(argv[i] + 12);
      else if (strncmp(argv[i], "client_port=", 12) == 0) {
        j = http_tokenize(argv[i] + 12, argv2, 2, '-');
        if (j > 0) {
          hc->hc_rtp_port = atoi(argv2[0]);
          if (hc->hc_rtp_port <= 0)
            return -EIO;
          if (j > 1) {
            hc->hc_rtcp_port = atoi(argv2[1]);
            if (hc->hc_rtcp_port <= 0)
              return -EIO;
          }
        } else {
          return -EIO;
        }
      }
      else if (strncmp(argv[i], "server_port=", 12) == 0) {
        j = http_tokenize(argv[i] + 12, argv2, 2, '-');
        if (j > 1) {
          hc->hc_rtcp_server_port = atoi(argv2[1]);
          if (hc->hc_rtcp_server_port <= 0)
            return -EIO;
        } else {
          return -EIO;
        }
      }
    }
  } else {
    return -EIO;
  }
  return HTTP_CON_OK;
}
Ejemplo n.º 9
0
int
main(int argc, char **argv)
{
  int i;
  sigset_t set;
#if ENABLE_LINUXDVB
  uint32_t adapter_mask;
#endif
  int  log_level   = LOG_INFO;
  int  log_options = TVHLOG_OPT_MILLIS | TVHLOG_OPT_STDERR | TVHLOG_OPT_SYSLOG;
  const char *log_debug = NULL, *log_trace = NULL;
  char buf[512];

  main_tid = pthread_self();

  /* Setup global mutexes */
  pthread_mutex_init(&ffmpeg_lock, NULL);
  pthread_mutex_init(&fork_lock, NULL);
  pthread_mutex_init(&global_lock, NULL);
  pthread_mutex_init(&atomic_lock, NULL);
  pthread_cond_init(&gtimer_cond, NULL);

  /* Defaults */
  tvheadend_webui_port      = 9981;
  tvheadend_webroot         = NULL;
  tvheadend_htsp_port       = 9982;
  tvheadend_htsp_port_extra = 0;

  /* Command line options */
  int         opt_help         = 0,
              opt_version      = 0,
              opt_fork         = 0,
              opt_firstrun     = 0,
              opt_stderr       = 0,
              opt_syslog       = 0,
              opt_uidebug      = 0,
              opt_abort        = 0,
              opt_noacl        = 0,
              opt_fileline     = 0,
              opt_threadid     = 0,
              opt_ipv6         = 0,
              opt_tsfile_tuner = 0,
              opt_dump         = 0;
  const char *opt_config       = NULL,
             *opt_user         = NULL,
             *opt_group        = NULL,
             *opt_logpath      = NULL,
             *opt_log_debug    = NULL,
             *opt_log_trace    = NULL,
             *opt_pidpath      = "/var/run/tvheadend.pid",
#if ENABLE_LINUXDVB
             *opt_dvb_adapters = NULL,
#endif
             *opt_bindaddr     = NULL,
             *opt_subscribe    = NULL;
  str_list_t  opt_tsfile       = { .max = 10, .num = 0, .str = calloc(10, sizeof(char*)) };
  cmdline_opt_t cmdline_opts[] = {
    {   0, NULL,        "Generic Options",         OPT_BOOL, NULL         },
    { 'h', "help",      "Show this page",          OPT_BOOL, &opt_help    },
    { 'v', "version",   "Show version infomation", OPT_BOOL, &opt_version },

    {   0, NULL,        "Service Configuration",   OPT_BOOL, NULL         },
    { 'c', "config",    "Alternate config path",   OPT_STR,  &opt_config  },
    { 'f', "fork",      "Fork and run as daemon",  OPT_BOOL, &opt_fork    },
    { 'u', "user",      "Run as user",             OPT_STR,  &opt_user    },
    { 'g', "group",     "Run as group",            OPT_STR,  &opt_group   },
    { 'p', "pid",       "Alternate pid path",      OPT_STR,  &opt_pidpath },
    { 'C', "firstrun",  "If no user account exists then create one with\n"
	                      "no username and no password. Use with care as\n"
	                      "it will allow world-wide administrative access\n"
	                      "to your Tvheadend installation until you edit\n"
	                      "the access-control from within the Tvheadend UI",
      OPT_BOOL, &opt_firstrun },
#if ENABLE_LINUXDVB
    { 'a', "adapters",  "Only use specified DVB adapters (comma separated)",
      OPT_STR, &opt_dvb_adapters },
#endif
    {   0, NULL,         "Server Connectivity",    OPT_BOOL, NULL         },
    { '6', "ipv6",       "Listen on IPv6",         OPT_BOOL, &opt_ipv6    },
    { 'b', "bindaddr",   "Specify bind address",   OPT_STR,  &opt_bindaddr},
    {   0, "http_port",  "Specify alternative http port",
      OPT_INT, &tvheadend_webui_port },
    {   0, "http_root",  "Specify alternative http webroot",
      OPT_STR, &tvheadend_webroot },
    {   0, "htsp_port",  "Specify alternative htsp port",
      OPT_INT, &tvheadend_htsp_port },
    {   0, "htsp_port2", "Specify extra htsp port",
      OPT_INT, &tvheadend_htsp_port_extra },

    {   0, NULL,        "Debug Options",           OPT_BOOL, NULL         },
    { 'd', "stderr",    "Enable debug on stderr",  OPT_BOOL, &opt_stderr  },
    { 's', "syslog",    "Enable debug to syslog",  OPT_BOOL, &opt_syslog  },
    { 'l', "logfile",   "Enable debug to file",    OPT_STR,  &opt_logpath },
    {   0, "debug",     "Enable debug subsystems", OPT_STR,  &opt_log_debug },
#if ENABLE_TRACE
    {   0, "trace",     "Enable trace subsystems", OPT_STR,  &opt_log_trace },
#endif
    {   0, "fileline",  "Add file and line numbers to debug", OPT_BOOL, &opt_fileline },
    {   0, "threadid",  "Add the thread ID to debug", OPT_BOOL, &opt_threadid },
    {   0, "uidebug",   "Enable webUI debug (non-minified JS)", OPT_BOOL, &opt_uidebug },
    { 'A', "abort",     "Immediately abort",       OPT_BOOL, &opt_abort   },
    { 'D', "dump",      "Enable coredumps for daemon", OPT_BOOL, &opt_dump },
    {   0, "noacl",     "Disable all access control checks",
      OPT_BOOL, &opt_noacl },
    { 'j', "join",      "Subscribe to a service permanently",
      OPT_STR, &opt_subscribe },


    { 0, NULL, "TODO: testing", OPT_BOOL, NULL },
    { 0, "tsfile_tuners", "Number of tsfile tuners", OPT_INT, &opt_tsfile_tuner },
    { 0, "tsfile", "tsfile input (mux file)", OPT_STR_LIST, &opt_tsfile },

  };

  /* Get current directory */
  tvheadend_cwd = dirname(dirname(tvh_strdupa(argv[0])));

  /* Set locale */
  setlocale(LC_ALL, "");
  setlocale(LC_NUMERIC, "C");

  /* make sure the timezone is set */
  tzset();

  /* Process command line */
  for (i = 1; i < argc; i++) {

    /* Find option */
    cmdline_opt_t *opt
      = cmdline_opt_find(cmdline_opts, ARRAY_SIZE(cmdline_opts), argv[i]);
    if (!opt)
      show_usage(argv[0], cmdline_opts, ARRAY_SIZE(cmdline_opts),
                 "invalid option specified [%s]", argv[i]);

    /* Process */
    if (opt->type == OPT_BOOL)
      *((int*)opt->param) = 1;
    else if (++i == argc)
      show_usage(argv[0], cmdline_opts, ARRAY_SIZE(cmdline_opts),
                 "option %s requires a value", opt->lopt);
    else if (opt->type == OPT_INT)
      *((int*)opt->param) = atoi(argv[i]);
    else if (opt->type == OPT_STR_LIST) {
      str_list_t *strl = opt->param;
      if (strl->num < strl->max)
        strl->str[strl->num++] = argv[i];
    }
    else
      *((char**)opt->param) = argv[i];

    /* Stop processing */
    if (opt_help)
      show_usage(argv[0], cmdline_opts, ARRAY_SIZE(cmdline_opts), NULL);
    if (opt_version)
      show_version(argv[0]);
  }

  /* Additional cmdline processing */
#if ENABLE_LINUXDVB
  if (!opt_dvb_adapters) {
    adapter_mask = ~0;
  } else {
    char *p, *e;
    char *r = NULL;
    char *dvb_adapters = strdup(opt_dvb_adapters);
    adapter_mask = 0x0;
    p = strtok_r(dvb_adapters, ",", &r);
    while (p) {
      int a = strtol(p, &e, 10);
      if (*e != 0 || a < 0 || a > 31) {
        tvhlog(LOG_ERR, "START", "Invalid adapter number '%s'", p);
        free(dvb_adapters);
        return 1;
      }
      adapter_mask |= (1 << a);
      p = strtok_r(NULL, ",", &r);
    }
    free(dvb_adapters);
    if (!adapter_mask) {
      tvhlog(LOG_ERR, "START", "No adapters specified!");
      return 1;
    }
  }
#endif
  if (tvheadend_webroot) {
    char *tmp;
    if (*tvheadend_webroot == '/')
      tmp = strdup(tvheadend_webroot);
    else {
      tmp = malloc(strlen(tvheadend_webroot)+2);
      *tmp = '/';
      strcpy(tmp+1, tvheadend_webroot);
    }
    if (tmp[strlen(tmp)-1] == '/')
      tmp[strlen(tmp)-1] = '\0';
    tvheadend_webroot = tmp;
  }
  tvheadend_webui_debug = opt_uidebug;

  /* Setup logging */
  if (isatty(2))
    log_options |= TVHLOG_OPT_DECORATE;
  if (opt_stderr || opt_syslog || opt_logpath) {
    if (!opt_log_trace && !opt_log_debug)
      log_debug      = "all";
    log_level      = LOG_DEBUG;
    if (opt_stderr)
      log_options   |= TVHLOG_OPT_DBG_STDERR;
    if (opt_syslog)
      log_options   |= TVHLOG_OPT_DBG_SYSLOG;
    if (opt_logpath)
      log_options   |= TVHLOG_OPT_DBG_FILE;
  }
  if (opt_fileline)
    log_options |= TVHLOG_OPT_FILELINE;
  if (opt_threadid)
    log_options |= TVHLOG_OPT_THREAD;
  if (opt_log_trace) {
    log_level  = LOG_TRACE;
    log_trace  = opt_log_trace;
  }
  if (opt_log_debug)
    log_debug  = opt_log_debug;
    
  tvhlog_init(log_level, log_options, opt_logpath);
  tvhlog_set_debug(log_debug);
  tvhlog_set_trace(log_trace);
 
  signal(SIGPIPE, handle_sigpipe); // will be redundant later

  /* Daemonise */
  if(opt_fork) {
    const char *homedir;
    gid_t gid;
    uid_t uid;
    struct group  *grp = getgrnam(opt_group ?: "video");
    struct passwd *pw  = opt_user ? getpwnam(opt_user) : NULL;
    FILE   *pidfile    = fopen(opt_pidpath, "w+");

    if(grp != NULL) {
      gid = grp->gr_gid;
    } else {
      gid = 1;
    }

    if (pw != NULL) {
      if (getuid() != pw->pw_uid) {
        gid_t glist[10];
        int gnum;
        gnum = get_user_groups(pw, glist, 10);
        if (setgroups(gnum, glist)) {
          tvhlog(LOG_ALERT, "START",
                 "setgroups() failed, do you have permission?");
          return 1;
        }
      }
      uid     = pw->pw_uid;
      homedir = pw->pw_dir;
      setenv("HOME", homedir, 1);
    } else {
      uid = 1;
    }
    if ((getgid() != gid) && setgid(gid)) {
      tvhlog(LOG_ALERT, "START",
             "setgid() failed, do you have permission?");
      return 1;
    }
    if ((getuid() != uid) && setuid(uid)) {
      tvhlog(LOG_ALERT, "START",
             "setuid() failed, do you have permission?");
      return 1;
    }

    if(daemon(0, 0)) {
      exit(2);
    }
    if(pidfile != NULL) {
      fprintf(pidfile, "%d\n", getpid());
      fclose(pidfile);
    }

    /* Make dumpable */
    if (opt_dump) {
#ifdef PLATFORM_LINUX
      if (chdir("/tmp"))
        tvhwarn("START", "failed to change cwd to /tmp");
      prctl(PR_SET_DUMPABLE, 1);
#else
      tvhwarn("START", "Coredumps not implemented on your platform");
#endif
    }

    umask(0);
  }

  tvheadend_running = 1;

  /* Start log thread (must be done post fork) */
  tvhlog_start();

  /* Alter logging */
  if (opt_fork)
    tvhlog_options &= ~TVHLOG_OPT_STDERR;
  if (!isatty(2))
    tvhlog_options &= ~TVHLOG_OPT_DECORATE;
  
  /* Initialise clock */
  pthread_mutex_lock(&global_lock);
  time(&dispatch_clock);

  /* Signal handling */
  sigfillset(&set);
  sigprocmask(SIG_BLOCK, &set, NULL);
  trap_init(argv[0]);
  
  /* Initialise configuration */
  uuid_init();
  idnode_init();
  config_init(opt_config);

  /**
   * Initialize subsystems
   */
  
  api_init();

  fsmonitor_init();

#if ENABLE_LIBAV
  libav_init();
  transcoding_init();
#endif

  imagecache_init();

  service_init();

#if ENABLE_TSFILE
  if(opt_tsfile.num) {
    tsfile_init(opt_tsfile_tuner ?: opt_tsfile.num);
    for (i = 0; i < opt_tsfile.num; i++)
      tsfile_add_file(opt_tsfile.str[i]);
  }
#endif
#if ENABLE_MPEGTS_DVB
  dvb_network_init();
#endif
#if ENABLE_IPTV
  iptv_init();
#endif
#if ENABLE_LINUXDVB
  linuxdvb_init(adapter_mask);
#endif

  channel_init();

  subscription_init();

  access_init(opt_firstrun, opt_noacl);

#if ENABLE_TIMESHIFT
  timeshift_init();
#endif

  http_client_init();
  tcp_server_init(opt_ipv6);
  http_server_init(opt_bindaddr);
  webui_init();

  service_mapper_init();

  descrambler_init();

  epggrab_init();
  epg_init();

  dvr_init();

  htsp_init(opt_bindaddr);


  if(opt_subscribe != NULL)
    subscription_dummy_join(opt_subscribe, 1);

  avahi_init();

  epg_updated(); // cleanup now all prev ref's should have been created

  pthread_mutex_unlock(&global_lock);

  /**
   * Wait for SIGTERM / SIGINT, but only in this thread
   */

  sigemptyset(&set);
  sigaddset(&set, SIGTERM);
  sigaddset(&set, SIGINT);

  signal(SIGTERM, doexit);
  signal(SIGINT, doexit);

  pthread_sigmask(SIG_UNBLOCK, &set, NULL);

  tvhlog(LOG_NOTICE, "START", "HTS Tvheadend version %s started, "
         "running as PID:%d UID:%d GID:%d, CWD:%s CNF:%s",
         tvheadend_version,
         getpid(), getuid(), getgid(), getcwd(buf, sizeof(buf)),
         hts_settings_get_root());

  if(opt_abort)
    abort();

  mainloop();

  tvhftrace("main", htsp_done);
  tvhftrace("main", http_server_done);
  tvhftrace("main", webui_done);
  tvhftrace("main", http_client_done);
  tvhftrace("main", fsmonitor_done);
#if ENABLE_MPEGTS_DVB
  tvhftrace("main", dvb_network_done);
#endif
#if ENABLE_IPTV
  tvhftrace("main", iptv_done);
#endif
#if ENABLE_LINUXDVB
  tvhftrace("main", linuxdvb_done);
#endif
#if ENABLE_TSFILE
  tvhftrace("main", tsfile_done);
#endif

  // Note: the locking is obviously a bit redundant, but without
  //       we need to disable the gtimer_arm call in epg_save()
  pthread_mutex_lock(&global_lock);
  tvhftrace("main", epg_save);

#if ENABLE_TIMESHIFT
  tvhftrace("main", timeshift_term);
#endif
  pthread_mutex_unlock(&global_lock);

  tvhftrace("main", epggrab_done);
  tvhftrace("main", tcp_server_done);
  tvhftrace("main", descrambler_done);
  tvhftrace("main", service_mapper_done);
  tvhftrace("main", service_done);
  tvhftrace("main", channel_done);
  tvhftrace("main", dvr_done);
  tvhftrace("main", subscription_done);
  tvhftrace("main", access_done);
  tvhftrace("main", epg_done);
  tvhftrace("main", avahi_done);
  tvhftrace("main", imagecache_done);
  tvhftrace("main", idnode_done);
  tvhftrace("main", lang_code_done);
  tvhftrace("main", api_done);
  tvhftrace("main", config_done);
  tvhftrace("main", hts_settings_done);
  tvhftrace("main", dvb_done);
  tvhftrace("main", lang_str_done);

  tvhlog(LOG_NOTICE, "STOP", "Exiting HTS Tvheadend");
  tvhlog_end();

  if(opt_fork)
    unlink(opt_pidpath);
    
  free(opt_tsfile.str);

  return 0;
}
Ejemplo n.º 10
0
int
h264_decode_slice_header(elementary_stream_t *st, bitstream_t *bs, int *pkttype,
			 int *isfield)
{
  h264_private_t *p;
  h264_pps_t *pps;
  h264_sps_t *sps;
  uint32_t slice_type, pps_id, width, height, v;
  uint64_t d;

  *pkttype = 0;
  *isfield = 0;

  if ((p = st->es_priv) == NULL)
    return -1;

  read_golomb_ue(bs); /* first_mb_in_slice */
  slice_type = read_golomb_ue(bs);

  if (slice_type > 4)
    slice_type -= 5;  /* Fixed slice type per frame */

  pps_id = read_golomb_ue(bs);
  if (pps_id >= MAX_PPS_COUNT)
    return -1;
  pps = &p->pps[pps_id];
  if (!pps->valid)
    return -1;
  sps = &p->sps[pps->sps_id];
  if (!sps->valid)
    return -1;

  if (!sps->max_frame_num_bits)
    return -1;

  switch(slice_type) {
  case 0:
    *pkttype = PKT_P_FRAME;
    break;
  case 1:
    *pkttype = PKT_B_FRAME;
    break;
  case 2:
    *pkttype = PKT_I_FRAME;
    break;
  default:
    return -1;
  }

  skip_bits(bs, sps->max_frame_num_bits);

  if (!sps->mbs_only_flag)
    if (read_bits1(bs)) {
      skip_bits1(bs); // bottom field
      *isfield = 1;
    }

  d = 0;
  if (sps->time_scale)
    d = 180000 * (uint64_t)sps->units_in_tick / (uint64_t)sps->time_scale;
  if (d == 0 && st->es_frame_duration == 0 && p->start + 4 < dispatch_clock) {
    tvhwarn("parser", "H264 stream has not timing information, using 30fps");
    d = 3000; /* 90000/30 = 3000 : 30fps */
  }

  if (sps->cbpsize)
    st->es_vbv_size = sps->cbpsize;

  st->es_vbv_delay = -1;

  width  = sps->width;
  height = sps->height * (2 - sps->mbs_only_flag);

  if (width && height && d)
    parser_set_stream_vparam(st, width, height, d);

  if (sps->aspect_num && sps->aspect_den) {
    width  *= sps->aspect_num;
    height *= sps->aspect_den;
    if (width && height) {
      v = gcdU32(width, height);
      st->es_aspect_num = width / v;
      st->es_aspect_den = height / v;
    }
  } else {
    st->es_aspect_num = 0;
    st->es_aspect_den = 1;
  }

  return 0;
}
Ejemplo n.º 11
0
udp_connection_t *
udp_bind ( const char *subsystem, const char *name,
           const char *bindaddr, int port,
           const char *ifname, int rxsize )
{
  int fd, ifindex, reuse = 1;
  udp_connection_t *uc;
  char buf[256];
  socklen_t addrlen;

  uc = calloc(1, sizeof(udp_connection_t));
  uc->fd                   = -1;
  uc->host                 = bindaddr ? strdup(bindaddr) : NULL;
  uc->port                 = port;
  uc->ifname               = ifname ? strdup(ifname) : NULL;
  uc->subsystem            = subsystem ? strdup(subsystem) : NULL;
  uc->name                 = name ? strdup(name) : NULL;
  uc->rxtxsize             = rxsize;

  if (udp_resolve(uc, 1) < 0) {
    udp_close(uc);
    return UDP_FATAL_ERROR;
  }

  /* Open socket */
  if ((fd = tvh_socket(uc->ip.ss_family, SOCK_DGRAM, 0)) == -1) {
    tvherror(subsystem, "%s - failed to create socket [%s]",
             name, strerror(errno));
    udp_close(uc);
    return UDP_FATAL_ERROR;
  }

  /* Mark reuse address */
  setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));

  /* Bind to interface */
  ifindex = udp_ifindex_required(uc) ? udp_get_ifindex(ifname) : 0;
  if (ifindex < 0) {
    tvherror(subsystem, "%s - could not find interface %s",
             name, ifname);
    goto error;
  }

  /* IPv4 */
  if (uc->ip.ss_family == AF_INET) {
#if defined(PLATFORM_DARWIN)
    struct ip_mreq       m;
#else
    struct ip_mreqn      m;
#endif
    memset(&m,   0, sizeof(m));

    /* Bind */
    if (bind(fd, (struct sockaddr *)&uc->ip, sizeof(struct sockaddr_in)) == -1) {
      inet_ntop(AF_INET, &IP_AS_V4(uc->ip, addr), buf, sizeof(buf));
      tvherror(subsystem, "%s - cannot bind %s:%hu [e=%s]",
               name, buf, ntohs(IP_AS_V4(uc->ip, port)), strerror(errno));
      goto error;
    }

    if (uc->multicast) {
      /* Join group */
      m.imr_multiaddr      = IP_AS_V4(uc->ip, addr);
#if !defined(PLATFORM_DARWIN)
      m.imr_address.s_addr = 0;
      m.imr_ifindex        = ifindex;
#else
      if (udp_get_ifaddr(fd, ifname, &m.imr_interface) == -1) {
        tvherror(subsystem, "%s - cannot find ip address for interface %s [e=%s]",
                 name, ifname,  strerror(errno));
        goto error;
      }
#endif

      if (setsockopt(fd, udp_get_solip(), IP_ADD_MEMBERSHIP, &m, sizeof(m))) {
        inet_ntop(AF_INET, &m.imr_multiaddr, buf, sizeof(buf));
        tvhwarn(subsystem, "%s - cannot join %s [%s]",
                name, buf, strerror(errno));
      }
   }

  /* Bind to IPv6 group */
  } else {
    struct ipv6_mreq m;
    memset(&m,   0, sizeof(m));

    /* Bind */
    if (bind(fd, (struct sockaddr *)&uc->ip, sizeof(struct sockaddr_in6)) == -1) {
      inet_ntop(AF_INET6, &IP_AS_V6(uc->ip, addr), buf, sizeof(buf));
      tvherror(subsystem, "%s - cannot bind %s:%hu [e=%s]",
               name, buf, ntohs(IP_AS_V6(uc->ip, port)), strerror(errno));
      goto error;
    }

    if (uc->multicast) {
      /* Join group */
      m.ipv6mr_multiaddr = IP_AS_V6(uc->ip, addr);
      m.ipv6mr_interface = ifindex;
#ifdef SOL_IPV6
      if (setsockopt(fd, SOL_IPV6, IPV6_ADD_MEMBERSHIP, &m, sizeof(m))) {
        inet_ntop(AF_INET, &m.ipv6mr_multiaddr, buf, sizeof(buf));
        tvhwarn(subsystem, "%s - cannot join %s [%s]",
                name, buf, strerror(errno));
      }
#else
      tvherror(subsystem, "IPv6 multicast not supported");
      goto error;
#endif
    }
  }

  addrlen = sizeof(uc->ip);
  getsockname(fd, (struct sockaddr *)&uc->ip, &addrlen);
    
  /* Increase RX buffer size */
  if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rxsize, sizeof(rxsize)) == -1)
    tvhwarn(subsystem, "%s - cannot increase UDP rx buffer size [%s]",
            name, strerror(errno));

  uc->fd = fd;
  return uc;

error:
  udp_close(uc);
  return NULL;
}
Ejemplo n.º 12
0
/**
 * Write a packet to the muxer
 */
static int
lav_muxer_write_pkt(muxer_t *m, streaming_message_type_t smt, void *data)
{
  int i;
  AVFormatContext *oc;
  AVStream *st;
  AVPacket packet;
  enum AVCodecID codec_id;
  th_pkt_t *pkt = (th_pkt_t*)data, *opkt;
  lav_muxer_t *lm = (lav_muxer_t*)m;
  unsigned char *tofree;
  int rc = 0;

  assert(smt == SMT_PACKET);

  oc = lm->lm_oc;

  if(!oc->nb_streams) {
    tvherror(LS_LIBAV, "No streams to mux");
    rc = -1;
    goto ret;
  }

  if(!lm->lm_init) {
    tvherror(LS_LIBAV, "Muxer not initialized correctly");
    rc = -1;
    goto ret;
  }

  for(i=0; i<oc->nb_streams; i++) {
    st = oc->streams[i];

    if(st->id != pkt->pkt_componentindex)
      continue;
    if(pkt->pkt_payload == NULL)
      continue;

    tofree = NULL;
    av_init_packet(&packet);
    codec_id = st->codec->codec_id;

    if((lm->lm_h264_filter && codec_id == AV_CODEC_ID_H264) ||
       (lm->lm_hevc_filter && codec_id == AV_CODEC_ID_HEVC)) {
      pkt = avc_convert_pkt(opkt = pkt);
      pkt_ref_dec(opkt);
      if(av_bitstream_filter_filter(st->codec->codec_id == AV_CODEC_ID_H264 ?
                                      lm->lm_h264_filter : lm->lm_hevc_filter,
				    st->codec, 
				    NULL, 
				    &packet.data, 
				    &packet.size, 
				    pktbuf_ptr(pkt->pkt_payload), 
				    pktbuf_len(pkt->pkt_payload), 
				    pkt->pkt_frametype < PKT_P_FRAME) < 0) {
	tvhwarn(LS_LIBAV,  "Failed to filter bitstream");
	if (packet.data != pktbuf_ptr(pkt->pkt_payload))
	  av_free(packet.data);
	break;
      } else {
        tofree = packet.data;
      }
    } else if (codec_id == AV_CODEC_ID_AAC) {
      /* remove ADTS header */
      packet.data = pktbuf_ptr(pkt->pkt_payload) + 7;
      packet.size = pktbuf_len(pkt->pkt_payload) - 7;
    } else {
      if (lm->m_config.m_type == MC_AVMP4 &&
          (codec_id == AV_CODEC_ID_H264 || codec_id == AV_CODEC_ID_HEVC)) {
        pkt = avc_convert_pkt(opkt = pkt);
        pkt_ref_dec(opkt);
      }
      packet.data = pktbuf_ptr(pkt->pkt_payload);
      packet.size = pktbuf_len(pkt->pkt_payload);
    }


    packet.stream_index = st->index;
 
    packet.pts      = av_rescale_q(pkt->pkt_pts     , mpeg_tc, st->time_base);
    packet.dts      = av_rescale_q(pkt->pkt_dts     , mpeg_tc, st->time_base);
    packet.duration = av_rescale_q(pkt->pkt_duration, mpeg_tc, st->time_base);

    if(pkt->pkt_frametype < PKT_P_FRAME)
      packet.flags |= AV_PKT_FLAG_KEY;

    if((rc = av_interleaved_write_frame(oc, &packet)))
      tvhwarn(LS_LIBAV,  "Failed to write frame");

    if(tofree && tofree != pktbuf_ptr(pkt->pkt_payload))
      av_free(tofree);

    break;
  }

 ret:
  lm->m_errors += (rc != 0);
  pkt_ref_dec(pkt);

  return rc;
}
Ejemplo n.º 13
0
/**
 * Init the muxer with streams
 */
static int
lav_muxer_init(muxer_t* m, struct streaming_start *ss, const char *name)
{
  int i;
  streaming_start_component_t *ssc;
  AVFormatContext *oc;
  AVDictionary *opts = NULL;
  lav_muxer_t *lm = (lav_muxer_t*)m;
  char app[128];

  snprintf(app, sizeof(app), "Tvheadend %s", tvheadend_version);

  oc = lm->lm_oc;

  av_dict_set(&oc->metadata, "title", name, 0);
  av_dict_set(&oc->metadata, "service_name", name, 0);
  av_dict_set(&oc->metadata, "service_provider", app, 0);

  if(lm->m_config.m_type == MC_MPEGTS) {
    lm->lm_h264_filter = av_bitstream_filter_init("h264_mp4toannexb");
    lm->lm_hevc_filter = av_bitstream_filter_init("hevc_mp4toannexb");
  }

  oc->max_delay = 0.7 * AV_TIME_BASE;

  for(i=0; i < ss->ss_num_components; i++) {
    ssc = &ss->ss_components[i];

    if(ssc->ssc_disabled)
      continue;

    if(!lav_muxer_support_stream(lm->m_config.m_type, ssc->ssc_type)) {
      tvhwarn(LS_LIBAV,  "%s is not supported in %s", 
	      streaming_component_type2txt(ssc->ssc_type), 
	      muxer_container_type2txt(lm->m_config.m_type));
      ssc->ssc_muxer_disabled = 1;
      continue;
    }

    if(lav_muxer_add_stream(lm, ssc)) {
      tvherror(LS_LIBAV,  "Failed to add %s stream", 
	       streaming_component_type2txt(ssc->ssc_type));
      ssc->ssc_muxer_disabled = 1;
      continue;
    }
  }

  if(lm->m_config.m_type == MC_AVMP4) {
    av_dict_set(&opts, "frag_duration", "1", 0);
    av_dict_set(&opts, "ism_lookahead", "0", 0);
  }

  if(!lm->lm_oc->nb_streams) {
    tvherror(LS_LIBAV,  "No supported streams available");
    lm->m_errors++;
    return -1;
  } else if(avformat_write_header(lm->lm_oc, &opts) < 0) {
    tvherror(LS_LIBAV,  "Failed to write %s header", 
	     muxer_container_type2txt(lm->m_config.m_type));
    lm->m_errors++;
    return -1;
  }

  if (opts)
    av_dict_free(&opts);

  lm->lm_init = 1;

  return 0;
}