Beispiel #1
0
/* Checks if the file path is configured to be ignored */
static int
file_path_ignore(const char *path)
{
  cfg_t *lib;
  regex_t regex;
  int n;
  int i;
  int ret;

  lib = cfg_getsec(cfg, "library");
  n = cfg_size(lib, "filepath_ignore");

  for (i = 0; i < n; i++)
    {
      ret = regcomp(&regex, cfg_getnstr(lib, "filepath_ignore", i), 0);
      if (ret != 0)
	{
	  DPRINTF(E_LOG, L_SCAN, "Could not compile regex for matching with file path\n");
	  return 0;
	}

      ret = regexec(&regex, path, 0, NULL, 0);
      regfree(&regex);

      if (ret == 0)
	{
	  DPRINTF(E_DBG, L_SCAN, "Regex match: %s\n", path);
	  return 1;
	}
    }

  return 0;
}
Beispiel #2
0
int Settings::setIntSetting(Node type, int intDeviceId, const std::wstring &name, int value, bool parameter) {
	// already locked
	if (d->cfg == 0) {
		return TELLSTICK_ERROR_PERMISSION_DENIED;
	}
	std::string strType = getNodeString(type);
	cfg_t *cfg_device;
	for (int i = 0; i < cfg_size(d->cfg, strType.c_str()); ++i) {
		cfg_device = cfg_getnsec(d->cfg, strType.c_str(), i);
		if (cfg_getint(cfg_device, "id") == intDeviceId)  {
			if (parameter) {
				cfg_t *cfg_parameters = cfg_getsec(cfg_device, "parameters");
				cfg_setint(cfg_parameters, TelldusCore::wideToString(name).c_str(), value);
			} else {
				cfg_setint(cfg_device, TelldusCore::wideToString(name).c_str(), value);
			}
			FILE *fp = fopen(CONFIG_FILE, "we");  // e for setting O_CLOEXEC on the file handle
			if (!fp) {
				return TELLSTICK_ERROR_PERMISSION_DENIED;
			}
			cfg_print(d->cfg, fp);
			fclose(fp);
			return TELLSTICK_SUCCESS;
		}
	}
	return TELLSTICK_ERROR_DEVICE_NOT_FOUND;
}
Beispiel #3
0
static cfg_t* find_module_config(char *modname)
{
    cfg_t *modules_cfg;
    int j;

    modules_cfg = cfg_getsec(python_module.config_file, "modules");
    for (j = 0; j < cfg_size(modules_cfg, "module"); j++) {
        char *modName, *modLanguage;
        int modEnabled;

        cfg_t *pymodule = cfg_getnsec(modules_cfg, "module", j);

        /* Check the module language to make sure that
           the language designation is python.
        */
        modLanguage = cfg_getstr(pymodule, "language");
        if (!modLanguage || strcasecmp(modLanguage, "python")) 
            continue;

        modName = cfg_getstr(pymodule, "name");
        if (strcasecmp(modname, modName)) {
            continue;
        }

        /* Check to make sure that the module is enabled.
        */
        modEnabled = cfg_getbool(pymodule, "enabled");
        if (!modEnabled) 
            continue;

        return pymodule;
    }
    return NULL; 
}
static int 
ignore_pl(plist_t pl, const char *name)
{
  uint64_t kind;
  int smart;
  uint8_t master;
  uint8_t party;

  kind = 0;
  smart = 0;
  master = 0;
  party = 0;

  /* Special (builtin) playlists */
  get_dictval_int_from_key(pl, "Distinguished Kind", &kind);

  /* Import smart playlists (optional) */
  if (!cfg_getbool(cfg_getsec(cfg, "library"), "itunes_smartpl")
      && (plist_dict_get_item(pl, "Smart Info") || plist_dict_get_item(pl, "Smart Criteria")))
    smart = 1;

  /* Not interested in the Master playlist */
  get_dictval_bool_from_key(pl, "Master", &master);
  /* Not interested in Party Shuffle playlists */
  get_dictval_bool_from_key(pl, "Party Shuffle", &party);

  if ((kind > 0) || smart || party || master)
    {
      DPRINTF(E_INFO, L_SCAN, "Ignoring playlist '%s' (k %" PRIu64 " s%d p%d m%d)\n", name, kind, smart, party, master);

      return 1;
    }

  return 0;
}
Beispiel #5
0
int
laudio_init(laudio_status_cb cb)
{
    snd_lib_error_set_handler(logger_alsa);

    status_cb = cb;

    card_name = cfg_getstr(cfg_getsec(cfg, "audio"), "card");
    mixer_name = cfg_getstr(cfg_getsec(cfg, "audio"), "mixer");

    hdl = NULL;
    mixer_hdl = NULL;
    vol_elem = NULL;

    return 0;
}
int
laudio_init(laudio_status_cb cb)
{
  status_cb = cb;

  card_name = cfg_getstr(cfg_getsec(cfg, "audio"), "card");

  return 0;
}
Beispiel #7
0
static void
initscan()
{
  time_t starttime;
  time_t endtime;
  bool clear_queue_disabled;
  int i;

  scanning = true;
  starttime = time(NULL);
  listener_notify(LISTENER_UPDATE);

  // Only clear the queue if enabled (default) in config
  clear_queue_disabled = cfg_getbool(cfg_getsec(cfg, "mpd"), "clear_queue_on_stop_disable");
  if (!clear_queue_disabled)
    {
      db_queue_clear(0);
    }

  for (i = 0; sources[i]; i++)
    {
      if (!sources[i]->disabled && sources[i]->initscan)
	sources[i]->initscan();
    }

  if (! (cfg_getbool(cfg_getsec(cfg, "library"), "filescan_disable")))
    {
      purge_cruft(starttime);

      DPRINTF(E_DBG, L_LIB, "Running post library scan jobs\n");
      db_hook_post_scan();
    }

  endtime = time(NULL);
  DPRINTF(E_LOG, L_LIB, "Library init scan completed in %.f sec (%d changes)\n", difftime(endtime, starttime), deferred_update_notifications);

  scanning = false;

  if (handle_deferred_update_notifications())
    listener_notify(LISTENER_UPDATE | LISTENER_DATABASE);
  else
    listener_notify(LISTENER_UPDATE);
}
Beispiel #8
0
void read_cfg_section(section_t *section, cfg_t *cfg_sec, std::stringstream &errors)
{
   static const char *funcname = "conf::read_cfg_section";

   for (auto &entry : *section)
   {
      char *name = const_cast<char *>(entry.first.c_str());
      bool required = entry.second.is_required();

      switch (entry.second.what_type())
      {
         case val_type::integer:
         {
            integer_t val;
            if (0 == (val = cfg_getint(cfg_sec, name))) {
               if (required) errors << "Required int-option '" << name << "' is not set." << std::endl; }
            else entry.second.set(val);
            break;
         }

         case val_type::string:
         {
            char *val;
            if (nullptr == (val = cfg_getstr(cfg_sec, name))) {
               if (required) errors << "Required str-option '" << name << "' is not set." << std::endl; }
            else entry.second.set(val);
            break;
         }

         case val_type::multistring:
         {
            if (nullptr == cfg_getstr(cfg_sec, name)) {
               if (required) errors << "Required multistr-option '" << name << "' is not set." << std::endl; }
            else
            {
               int count = cfg_size(cfg_sec, name);
               multistring_t strs;

               for (int i = 0; i < count; i++) 
                  strs.push_back(std::move(string_t(cfg_getnstr(cfg_sec, name, i))));
               entry.second.set(strs);
            }
            break;
         }

         case val_type::section:
            read_cfg_section(entry.second.get<conf::section_t *>(), cfg_getsec(cfg_sec, name), errors);
            break;

         case val_type::unknown:
            throw logging::error(funcname, "Val with unknown type in section: %s", name);   
      }
   }
}
Beispiel #9
0
static void
rsp_reply_info(struct evhttp_request *req, char **uri, struct evkeyvalq *query)
{
  mxml_node_t *reply;
  mxml_node_t *status;
  mxml_node_t *info;
  mxml_node_t *node;
  cfg_t *lib;
  char *library;
  int songcount;

  songcount = db_files_get_count();

  lib = cfg_getsec(cfg, "library");
  library = cfg_getstr(lib, "name");

  /* We'd use mxmlNewXML(), but then we can't put any attributes
   * on the root node and we need some.
   */
  reply = mxmlNewElement(MXML_NO_PARENT, RSP_XML_ROOT);

  node = mxmlNewElement(reply, "response");
  status = mxmlNewElement(node, "status");
  info = mxmlNewElement(node, "info");

  /* Status block */
  node = mxmlNewElement(status, "errorcode");
  mxmlNewText(node, 0, "0");

  node = mxmlNewElement(status, "errorstring");
  mxmlNewText(node, 0, "");

  node = mxmlNewElement(status, "records");
  mxmlNewText(node, 0, "0");

  node = mxmlNewElement(status, "totalrecords");
  mxmlNewText(node, 0, "0");

  /* Info block */
  node = mxmlNewElement(info, "count");
  mxmlNewTextf(node, 0, "%d", songcount);

  node = mxmlNewElement(info, "rsp-version");
  mxmlNewText(node, 0, RSP_VERSION);

  node = mxmlNewElement(info, "server-version");
  mxmlNewText(node, 0, VERSION);

  node = mxmlNewElement(info, "name");
  mxmlNewText(node, 0, library);

  rsp_send_reply(req, reply);
}
Beispiel #10
0
/* Thread: scan */
static void
bulk_scan(void)
{
  cfg_t *lib;
  int ndirs;
  char *path;
  char *deref;
  time_t start;
  int i;

  start = time(NULL);

  playlists = NULL;
  dirstack = NULL;

  lib = cfg_getsec(cfg, "library");

  ndirs = cfg_size(lib, "directories");
  for (i = 0; i < ndirs; i++)
    {
      path = cfg_getnstr(lib, "directories", i);

      deref = m_realpath(path);
      if (!deref)
	{
	  DPRINTF(E_LOG, L_SCAN, "Skipping library directory %s, could not dereference: %s\n", path, strerror(errno));

	  continue;
	}

      process_directories(deref, F_SCAN_BULK);

      free(deref);

      if (scan_exit)
	return;
    }

  if (playlists)
    process_deferred_playlists();

  if (scan_exit)
    return;

  if (dirstack)
    DPRINTF(E_LOG, L_SCAN, "WARNING: unhandled leftover directories\n");

  DPRINTF(E_DBG, L_SCAN, "Purging old database content\n");
  db_purge_cruft(start);
}
/* Thread: scan */
static int
check_speciallib(char *path, const char *libtype)
{
  cfg_t *lib;
  int ndirs;
  int i;

  lib = cfg_getsec(cfg, "library");
  ndirs = cfg_size(lib, libtype);
  for (i = 0; i < ndirs; i++)
    {
      if (strstr(path, cfg_getnstr(lib, libtype, i)))
	return 1;
    }

  return 0;
}
Beispiel #12
0
DLLIMPORT cfg_opt_t *cfg_getopt(cfg_t *cfg, const char *name)
{
	unsigned int i;
	cfg_t *sec = cfg;

	assert(cfg && cfg->name && name);

	while (name && *name) {
		char *secname;
		size_t len = strcspn(name, "|");

		if (name[len] == 0 /*len == strlen(name) */ )
			/* no more subsections */
			break;

		if (len) {
			secname = strndup(name, len);
			sec = cfg_getsec(sec, secname);
			if (!sec) {
				if (!(cfg->flags & CFGF_IGNORE_UNKNOWN))
					cfg_error(cfg, _("no such option '%s'"), secname);
				free(secname);
				return NULL;
			}
			free(secname);
		}
		name += len;
		name += strspn(name, "|");
	}

	for (i = 0; sec->opts[i].name; i++) {
		if (is_set(CFGF_NOCASE, sec->flags)) {
			if (strcasecmp(sec->opts[i].name, name) == 0)
				return &sec->opts[i];
		} else {
			if (strcmp(sec->opts[i].name, name) == 0)
				return &sec->opts[i];
		}
	}

	if (!(cfg->flags & CFGF_IGNORE_UNKNOWN))
		cfg_error(cfg, _("no such option '%s'"), name);

	return NULL;
}
Beispiel #13
0
int Settings::getIntSetting(Node type, int intDeviceId, const std::wstring &name, bool parameter) const {
	// already locked
	if (d->cfg == 0) {
		return 0;
	}
	std::string strType = getNodeString(type);
	cfg_t *cfg_node;
	for(int i = 0; i < cfg_size(d->cfg, strType.c_str()); ++i) {
		cfg_node = cfg_getnsec(d->cfg, strType.c_str(), i);
		if (cfg_getint(cfg_node, "id") == intDeviceId) {
			if (parameter) {
				cfg_node = cfg_getsec(cfg_node, "parameters");
			}
			return cfg_getint(cfg_node, TelldusCore::wideToString(name).c_str());
		}
	}
	return 0;
}
/* Checks if the file extension is in the ignore list */
static int
file_type_ignore(const char *ext)
{
  cfg_t *lib;
  int n;
  int i;

  lib = cfg_getsec(cfg, "library");
  n = cfg_size(lib, "filetypes_ignore");

  for (i = 0; i < n; i++)
    {
      if (strcasecmp(ext, cfg_getnstr(lib, "filetypes_ignore", i)) == 0)
	return 1;
    }

  return 0;
}
Beispiel #15
0
/* Thread: scan */
static int
check_compilation(char *path)
{
  cfg_t *lib;
  int ndirs;
  int i;

  lib = cfg_getsec(cfg, "library");
  ndirs = cfg_size(lib, "compilations");

  for (i = 0; i < ndirs; i++)
    {
      if (strstr(path, cfg_getnstr(lib, "compilations", i)))
	return 1;
    }

  return 0;
}
Beispiel #16
0
/** Initializer for this "SOM" */
void som_init(cfg_t *som_config) {
	if (!som_config) return;

	const char *protocol = cfg_getstr(som_config, "protocol");
	channel = cfg_getstr(som_config, "channel");

	info("Scheduler is initializing protocol [ \"%s\" ] on channel %s",
			protocol,channel);

	chunkbuffer = chbInit("size=256,time=now");
	if (!chunkbuffer) 
		fatal("Error initialising the Chunk Buffer");
	chbRegisterNotifier(chunkbuffer, chunkbuffer_notifier, NULL);

	int publishPeerIDPeriod =  cfg_getint(som_config,
			"publishPeerIDPeriod");
	if (publishPeerIDPeriod) 
		napaSchedulePeriodic(NULL, 1.0/(float)publishPeerIDPeriod,
				publish_PeerID, NULL);

	/* If we are passive, we need to figure out who is the server, and send
	 * a message to it for ML to be able to work... Sigh... */
	if (!strcmp(protocol, "passive")) {
		struct timeval t = { 0, 0 };
		event_base_once(eventbase, -1, EV_TIMEOUT, &findServer, NULL, &t);
	}

	/* If the string "neighborlist" is present in the protocol name, we
	 * launch a neighborlist instance */
	if (strstr(protocol, "neighborlist")) {
		cfg_t *nlist_cfg = cfg_getsec(som_config, "neighborlist");
		neighbors_size = cfg_getint(nlist_cfg, "size");

		neighbors = calloc(sizeof(NeighborListEntry), neighbors_size);

		neighborlist = neighborlist_init(repository, 
			neighbors_size,
			cfg_getint(nlist_cfg, "refreshPeriod"),
			channel,
			neighborlist_cb, NULL);
	}
}
Beispiel #17
0
std::wstring Settings::getStringSetting(Node type, int intNodeId, const std::wstring &name, bool parameter) const {
	// already locked
	if (d->cfg == 0) {
		return L"";
	}
	std::string strType = getNodeString(type);

	cfg_t *cfg_device;
	for (int i = 0; i < cfg_size(d->cfg, strType.c_str()); ++i) {
		cfg_device = cfg_getnsec(d->cfg, strType.c_str(), i);
		if (cfg_getint(cfg_device, "id") == intNodeId)  {
			if (parameter) {
				cfg_device = cfg_getsec(cfg_device, "parameters");
			}
			std::wstring setting;
			char *cSetting = cfg_getstr(cfg_device, TelldusCore::wideToString(name).c_str());
			if (cSetting) {
				setting = TelldusCore::charToWstring(cSetting);
			}
			return setting;
		}
	}
	return L"";
}
Beispiel #18
0
static int
register_services(char *ffid, int no_rsp, int no_daap)
{
  cfg_t *lib;
  char *libname;
  char *password;
  char *txtrecord[10];
  char records[9][128];
  int port;
  uint32_t hash;
  int i;
  int ret;

  srand((unsigned int)time(NULL));

  lib = cfg_getsec(cfg, "library");

  libname = cfg_getstr(lib, "name");
  hash = djb_hash(libname, strlen(libname));

  for (i = 0; i < (sizeof(records) / sizeof(records[0])); i++)
    {
      memset(records[i], 0, 128);
      txtrecord[i] = records[i];
    }

  txtrecord[9] = NULL;

  snprintf(txtrecord[0], 128, "txtvers=1");
  snprintf(txtrecord[1], 128, "Database ID=%0X", hash);
  snprintf(txtrecord[2], 128, "Machine ID=%0X", hash);
  snprintf(txtrecord[3], 128, "Machine Name=%s", libname);
  snprintf(txtrecord[4], 128, "mtd-version=%s", VERSION);
  snprintf(txtrecord[5], 128, "iTSh Version=131073"); /* iTunes 6.0.4 */
  snprintf(txtrecord[6], 128, "Version=196610");      /* iTunes 6.0.4 */

  password = cfg_getstr(lib, "password");
  snprintf(txtrecord[7], 128, "Password=%s", (password) ? "true" : "false");

  if (ffid)
    snprintf(txtrecord[8], 128, "ffid=%s", ffid);
  else
    snprintf(txtrecord[8], 128, "ffid=%08x", rand());

  DPRINTF(E_INFO, L_MAIN, "Registering rendezvous names\n");

  port = cfg_getint(lib, "port");

  /* Register web server service - disabled since we have no web interface */
/*  ret = mdns_register(libname, "_http._tcp", port, txtrecord);
  if (ret < 0)
    return ret;
*/
  /* Register RSP service */
  if (!no_rsp)
    {
      ret = mdns_register(libname, "_rsp._tcp", port, txtrecord);
      if (ret < 0)
	return ret;
    }

  /* Register DAAP service */
  if (!no_daap)
    {
      ret = mdns_register(libname, "_daap._tcp", port, txtrecord);
      if (ret < 0)
	return ret;
    }

  for (i = 0; i < (sizeof(records) / sizeof(records[0])); i++)
    {
      memset(records[i], 0, 128);
    }

  snprintf(txtrecord[0], 128, "txtvers=1");
  snprintf(txtrecord[1], 128, "DbId=%016" PRIX64, libhash);
  snprintf(txtrecord[2], 128, "DvTy=iTunes");
  snprintf(txtrecord[3], 128, "DvSv=2306"); /* Magic number! Yay! */
  snprintf(txtrecord[4], 128, "Ver=131073"); /* iTunes 6.0.4 */
  snprintf(txtrecord[5], 128, "OSsi=0x1F5"); /* Magic number! Yay! */
  snprintf(txtrecord[6], 128, "CtlN=%s", libname);

  /* Terminator */
  txtrecord[7] = NULL;

  /* The group name for the touch-able service advertising is a 64bit hash
   * but is different from the DbId in iTunes. For now we'll use a hash of
   * the library name for both, and we'll change that if needed.
   */

  /* Use as scratch space for the hash */
  snprintf(records[7], 128, "%016" PRIX64, libhash);

  /* Register touch-able service, for Remote.app */
  ret = mdns_register(records[7], "_touch-able._tcp", port, txtrecord);
  if (ret < 0)
    return ret;

  return 0;
}
Beispiel #19
0
static int
daemonize(int background, char *pidfile)
{
  FILE *fp;
  pid_t childpid;
  pid_t pid_ret;
  int fd;
  int ret;
  char *runas;

  if (background)
    {
      fp = fopen(pidfile, "w");
      if (!fp)
	{
	  DPRINTF(E_LOG, L_MAIN, "Error opening pidfile (%s): %s\n", pidfile, strerror(errno));

	  return -1;
	}

      fd = open("/dev/null", O_RDWR, 0);
      if (fd < 0)
	{
	  DPRINTF(E_LOG, L_MAIN, "Error opening /dev/null: %s\n", strerror(errno));

	  fclose(fp);
	  return -1;
	}

      signal(SIGTTOU, SIG_IGN);
      signal(SIGTTIN, SIG_IGN);
      signal(SIGTSTP, SIG_IGN);

      childpid = fork();

      if (childpid > 0)
	exit(EXIT_SUCCESS);
      else if (childpid < 0)
	{
	  DPRINTF(E_FATAL, L_MAIN, "Fork failed: %s\n", strerror(errno));

	  close(fd);
	  fclose(fp);
	  return -1;
	}

      pid_ret = setsid();
      if (pid_ret == (pid_t) -1)
	{
	  DPRINTF(E_FATAL, L_MAIN, "setsid() failed: %s\n", strerror(errno));

	  close(fd);
	  fclose(fp);
	  return -1;
	}

      logger_detach();

      dup2(fd, STDIN_FILENO);
      dup2(fd, STDOUT_FILENO);
      dup2(fd, STDERR_FILENO);

      if (fd > 2)
	close(fd);

      ret = chdir("/");
      if (ret < 0)
        DPRINTF(E_WARN, L_MAIN, "chdir() failed: %s\n", strerror(errno));

      umask(0);

      fprintf(fp, "%d\n", getpid());
      fclose(fp);

      DPRINTF(E_DBG, L_MAIN, "PID: %d\n", getpid());
    }

  if (geteuid() == (uid_t) 0)
    {
      runas = cfg_getstr(cfg_getsec(cfg, "general"), "uid");

      ret = initgroups(runas, runas_gid);
      if (ret != 0)
	{
	  DPRINTF(E_FATAL, L_MAIN, "initgroups() failed: %s\n", strerror(errno));

	  return -1;
	}

      ret = setegid(runas_gid);
      if (ret != 0)
	{
	  DPRINTF(E_FATAL, L_MAIN, "setegid() failed: %s\n", strerror(errno));

	  return -1;
	}

      ret = seteuid(runas_uid);
      if (ret != 0)
	{
	  DPRINTF(E_FATAL, L_MAIN, "seteuid() failed: %s\n", strerror(errno));

	  return -1;
	}
    }

  return 0;
}
Beispiel #20
0
/* Thread: httpd */
static void
serve_file(struct evhttp_request *req, char *uri)
{
  const char *host;
  char *ext;
  char path[PATH_MAX];
  char *deref;
  char *ctype;
  char *passwd;
  struct evbuffer *evbuf;
  struct evkeyvalq *headers;
  struct stat sb;
  int fd;
  int i;
  int ret;

  /* Check authentication */
  passwd = cfg_getstr(cfg_getsec(cfg, "general"), "admin_password");
  if (passwd)
    {
      DPRINTF(E_DBG, L_HTTPD, "Checking web interface authentication\n");

      ret = httpd_basic_auth(req, "admin", passwd, PACKAGE " web interface");
      if (ret != 0)
	return;

      DPRINTF(E_DBG, L_HTTPD, "Authentication successful\n");
    }
  else
    {
      host = evhttp_request_get_host(req);
      if ((strcmp(host, "::1") != 0)
	  && (strcmp(host, "127.0.0.1") != 0))
	{
	  DPRINTF(E_LOG, L_HTTPD, "Remote web interface request denied; no password set\n");

	  evhttp_send_error(req, 403, "Forbidden");
	  return;
	}
    }

  ret = snprintf(path, sizeof(path), "%s%s", WEBFACE_ROOT, uri + 1); /* skip starting '/' */
  if ((ret < 0) || (ret >= sizeof(path)))
    {
      DPRINTF(E_LOG, L_HTTPD, "Request exceeds PATH_MAX: %s\n", uri);

      evhttp_send_error(req, HTTP_NOTFOUND, "Not Found");

      return;
    }

  ret = lstat(path, &sb);
  if (ret < 0)
    {
      DPRINTF(E_LOG, L_HTTPD, "Could not lstat() %s: %s\n", path, strerror(errno));

      evhttp_send_error(req, HTTP_NOTFOUND, "Not Found");

      return;
    }

  if (S_ISDIR(sb.st_mode))
    {
      redirect_to_index(req, uri);

      return;
    }
  else if (S_ISLNK(sb.st_mode))
    {
      deref = m_realpath(path);
      if (!deref)
	{
	  DPRINTF(E_LOG, L_HTTPD, "Could not dereference %s: %s\n", path, strerror(errno));

	  evhttp_send_error(req, HTTP_NOTFOUND, "Not Found");

	  return;
	}

      if (strlen(deref) + 1 > PATH_MAX)
	{
	  DPRINTF(E_LOG, L_HTTPD, "Dereferenced path exceeds PATH_MAX: %s\n", path);

	  evhttp_send_error(req, HTTP_NOTFOUND, "Not Found");

	  free(deref);
	  return;
	}

      strcpy(path, deref);
      free(deref);

      ret = stat(path, &sb);
      if (ret < 0)
	{
	  DPRINTF(E_LOG, L_HTTPD, "Could not stat() %s: %s\n", path, strerror(errno));

	  evhttp_send_error(req, HTTP_NOTFOUND, "Not Found");

	  return;
	}

      if (S_ISDIR(sb.st_mode))
	{
	  redirect_to_index(req, uri);

	  return;
	}
    }

  if (path_is_legal(path) != 0)
    {
      evhttp_send_error(req, 403, "Forbidden");

      return;
    }

  evbuf = evbuffer_new();
  if (!evbuf)
    {
      DPRINTF(E_LOG, L_HTTPD, "Could not create evbuffer\n");

      evhttp_send_error(req, HTTP_SERVUNAVAIL, "Internal error");
      return;
    }

  fd = open(path, O_RDONLY);
  if (fd < 0)
    {
      DPRINTF(E_LOG, L_HTTPD, "Could not open %s: %s\n", path, strerror(errno));

      evhttp_send_error(req, HTTP_NOTFOUND, "Not Found");
      return;
    }

  /* FIXME: this is broken, if we ever need to serve files here,
   * this must be fixed.
   */
  ret = evbuffer_read(evbuf, fd, sb.st_size);
  close(fd);
  if (ret < 0)
    {
      DPRINTF(E_LOG, L_HTTPD, "Could not read file into evbuffer\n");

      evhttp_send_error(req, HTTP_SERVUNAVAIL, "Internal error");
      return;
    }

  ctype = "application/octet-stream";
  ext = strrchr(path, '.');
  if (ext)
    {
      for (i = 0; ext2ctype[i].ext; i++)
	{
	  if (strcmp(ext, ext2ctype[i].ext) == 0)
	    {
	      ctype = ext2ctype[i].ctype;
	      break;
	    }
	}
    }

  headers = evhttp_request_get_output_headers(req);

  evhttp_add_header(headers, "Content-Type", ctype);
  evhttp_send_reply(req, HTTP_OK, "OK", evbuf);

  evbuffer_free(evbuf);
}
Beispiel #21
0
/* Thread: main */
int
httpd_init(void)
{
  int v6enabled;
  unsigned short port;
  int ret;

  httpd_exit = 0;

  evbase_httpd = event_base_new();
  if (!evbase_httpd)
    {
      DPRINTF(E_FATAL, L_HTTPD, "Could not create an event base\n");

      return -1;
    }

  ret = rsp_init();
  if (ret < 0)
    {
      DPRINTF(E_FATAL, L_HTTPD, "RSP protocol init failed\n");

      goto rsp_fail;
    }

  ret = daap_init();
  if (ret < 0)
    {
      DPRINTF(E_FATAL, L_HTTPD, "DAAP protocol init failed\n");

      goto daap_fail;
    }

  ret = dacp_init();
  if (ret < 0)
    {
      DPRINTF(E_FATAL, L_HTTPD, "DACP protocol init failed\n");

      goto dacp_fail;
    }

  streaming_init();

#ifdef USE_EVENTFD
  exit_efd = eventfd(0, EFD_CLOEXEC);
  if (exit_efd < 0)
    {
      DPRINTF(E_FATAL, L_HTTPD, "Could not create eventfd: %s\n", strerror(errno));

      goto pipe_fail;
    }

  exitev = event_new(evbase_httpd, exit_efd, EV_READ, exit_cb, NULL);
#else
  ret = pipe2(exit_pipe, O_CLOEXEC);
  if (ret < 0)
    {
      DPRINTF(E_FATAL, L_HTTPD, "Could not create pipe: %s\n", strerror(errno));

      goto pipe_fail;
    }

  exitev = event_new(evbase_httpd, exit_pipe[0], EV_READ, exit_cb, NULL);
#endif /* USE_EVENTFD */
  if (!exitev)
    {
      DPRINTF(E_FATAL, L_HTTPD, "Could not create exit event\n");

      goto event_fail;
    }
  event_add(exitev, NULL);

  evhttpd = evhttp_new(evbase_httpd);
  if (!evhttpd)
    {
      DPRINTF(E_FATAL, L_HTTPD, "Could not create HTTP server\n");

      goto event_fail;
    }

  v6enabled = cfg_getbool(cfg_getsec(cfg, "general"), "ipv6");
  port = cfg_getint(cfg_getsec(cfg, "library"), "port");

  if (v6enabled)
    {
      ret = evhttp_bind_socket(evhttpd, "::", port);
      if (ret < 0)
	{
	  DPRINTF(E_LOG, L_HTTPD, "Could not bind to port %d, falling back to IPv4\n", port);
	  v6enabled = 0;
	}
    }

  if (!v6enabled)
    {
      ret = evhttp_bind_socket(evhttpd, "0.0.0.0", port);
      if (ret < 0)
	{
	  DPRINTF(E_FATAL, L_HTTPD, "Could not bind to port %d (forked-daapd already running?)\n", port);
	  goto bind_fail;
	}
    }

  evhttp_set_gencb(evhttpd, httpd_gen_cb, NULL);

  ret = pthread_create(&tid_httpd, NULL, httpd, NULL);
  if (ret != 0)
    {
      DPRINTF(E_FATAL, L_HTTPD, "Could not spawn HTTPd thread: %s\n", strerror(errno));

      goto thread_fail;
    }

  return 0;

 thread_fail:
 bind_fail:
  evhttp_free(evhttpd);
 event_fail:
#ifdef USE_EVENTFD
  close(exit_efd);
#else
  close(exit_pipe[0]);
  close(exit_pipe[1]);
#endif
 pipe_fail:
  streaming_deinit();
  dacp_deinit();
 dacp_fail:
  daap_deinit();
 daap_fail:
  rsp_deinit();
 rsp_fail:
  event_base_free(evbase_httpd);

  return -1;
}
Beispiel #22
0
void
rsp_request(struct evhttp_request *req)
{
  char *full_uri;
  char *uri;
  char *ptr;
  char *uri_parts[5];
  struct evkeyvalq query;
  cfg_t *lib;
  char *libname;
  char *passwd;
  int handler;
  int i;
  int ret;

  memset(&query, 0, sizeof(struct evkeyvalq));

  full_uri = httpd_fixup_uri(req);
  if (!full_uri)
    {
      rsp_send_error(req, "Server error");
      return;
    }

  ptr = strchr(full_uri, '?');
  if (ptr)
    *ptr = '\0';

  uri = strdup(full_uri);
  if (!uri)
    {
      rsp_send_error(req, "Server error");

      free(full_uri);
      return;
    }

  if (ptr)
    *ptr = '?';

  ptr = uri;
  uri = evhttp_decode_uri(uri);
  free(ptr);

  DPRINTF(E_DBG, L_RSP, "RSP request: %s\n", full_uri);

  handler = -1;
  for (i = 0; rsp_handlers[i].handler; i++)
    {
      ret = regexec(&rsp_handlers[i].preg, uri, 0, NULL, 0);
      if (ret == 0)
	{
	  handler = i;
	  break;
	}
    }

  if (handler < 0)
    {
      DPRINTF(E_LOG, L_RSP, "Unrecognized RSP request\n");

      rsp_send_error(req, "Bad path");

      free(uri);
      free(full_uri);
      return;
    }

  /* Check authentication */
  lib = cfg_getsec(cfg, "library");
  passwd = cfg_getstr(lib, "password");
  if (passwd)
    {
      libname = cfg_getstr(lib, "name");

      DPRINTF(E_DBG, L_HTTPD, "Checking authentication for library '%s'\n", libname);

      /* We don't care about the username */
      ret = httpd_basic_auth(req, NULL, passwd, libname);
      if (ret != 0)
	{
	  free(uri);
	  free(full_uri);
	  return;
	}

      DPRINTF(E_DBG, L_HTTPD, "Library authentication successful\n");
    }

  memset(uri_parts, 0, sizeof(uri_parts));

  uri_parts[0] = strtok_r(uri, "/", &ptr);
  for (i = 1; (i < sizeof(uri_parts) / sizeof(uri_parts[0])) && uri_parts[i - 1]; i++)
    {
      uri_parts[i] = strtok_r(NULL, "/", &ptr);
    }

  if (!uri_parts[0] || uri_parts[i - 1] || (i < 2))
    {
      DPRINTF(E_LOG, L_RSP, "RSP URI has too many/few components (%d)\n", (uri_parts[0]) ? i : 0);

      rsp_send_error(req, "Bad path");

      free(uri);
      free(full_uri);
      return;
    }

  evhttp_parse_query(full_uri, &query);

  rsp_handlers[handler].handler(req, uri_parts, &query);

  evhttp_clear_headers(&query);
  free(uri);
  free(full_uri);
}
Beispiel #23
0
static void
fixup_tags(struct media_file_info *mfi)
{
  cfg_t *lib;
  size_t len;
  char *tag;
  char *sep = " - ";
  char *ca;

  if (mfi->genre && (strlen(mfi->genre) == 0))
    {
      free(mfi->genre);
      mfi->genre = NULL;
    }

  if (mfi->artist && (strlen(mfi->artist) == 0))
    {
      free(mfi->artist);
      mfi->artist = NULL;
    }

  if (mfi->title && (strlen(mfi->title) == 0))
    {
      free(mfi->title);
      mfi->title = NULL;
    }

  /*
   * Default to mpeg4 video/audio for unknown file types
   * in an attempt to allow streaming of DRM-afflicted files
   */
  if (mfi->codectype && strcmp(mfi->codectype, "unkn") == 0)
    {
      if (mfi->has_video)
	{
	  strcpy(mfi->codectype, "mp4v");
	  strcpy(mfi->type, "m4v");
	}
      else
	{
	  strcpy(mfi->codectype, "mp4a");
	  strcpy(mfi->type, "m4a");
	}
    }

  if (!mfi->artist)
    {
      if (mfi->orchestra && mfi->conductor)
	{
	  len = strlen(mfi->orchestra) + strlen(sep) + strlen(mfi->conductor);
	  tag = (char *)malloc(len + 1);
	  if (tag)
	    {
	      sprintf(tag,"%s%s%s", mfi->orchestra, sep, mfi->conductor);
	      mfi->artist = tag;
            }
        }
      else if (mfi->orchestra)
	{
	  mfi->artist = strdup(mfi->orchestra);
        }
      else if (mfi->conductor)
	{
	  mfi->artist = strdup(mfi->conductor);
        }
    }

  /* Handle TV shows, try to present prettier metadata */
  if (mfi->tv_series_name && strlen(mfi->tv_series_name) != 0)
    {
      mfi->media_kind = MEDIA_KIND_TVSHOW;  /* tv show */

      /* Default to artist = series_name */
      if (mfi->artist && strlen(mfi->artist) == 0)
	{
	  free(mfi->artist);
	  mfi->artist = NULL;
	}

      if (!mfi->artist)
	mfi->artist = strdup(mfi->tv_series_name);

      /* Default to album = "<series_name>, Season <season_num>" */
      if (mfi->album && strlen(mfi->album) == 0)
	{
	  free(mfi->album);
	  mfi->album = NULL;
	}

      if (!mfi->album)
	{
	  len = snprintf(NULL, 0, "%s, Season %u", mfi->tv_series_name, mfi->tv_season_num);

	  mfi->album = (char *)malloc(len + 1);
	  if (mfi->album)
	    sprintf(mfi->album, "%s, Season %u", mfi->tv_series_name, mfi->tv_season_num);
	}
    }

  /* Check the 4 top-tags are filled */
  if (!mfi->artist)
    mfi->artist = strdup("Unknown artist");
  if (!mfi->album)
    mfi->album = strdup("Unknown album");
  if (!mfi->genre)
    mfi->genre = strdup("Unknown genre");
  if (!mfi->title)
    {
      /* fname is left untouched by unicode_fixup_mfi() for
       * obvious reasons, so ensure it is proper UTF-8
       */
      mfi->title = unicode_fixup_string(mfi->fname, "ascii");
      if (mfi->title == mfi->fname)
	mfi->title = strdup(mfi->fname);
    }

  /* Ensure sort tags are filled, manipulated and normalized */
  sort_tag_create(&mfi->artist_sort, mfi->artist);
  sort_tag_create(&mfi->album_sort, mfi->album);
  sort_tag_create(&mfi->title_sort, mfi->title);

  /* We need to set album_artist according to media type and config */
  if (mfi->compilation)          /* Compilation */
    {
      lib = cfg_getsec(cfg, "library");
      ca = cfg_getstr(lib, "compilation_artist");
      if (ca && mfi->album_artist)
	{
	  free(mfi->album_artist);
	  mfi->album_artist = strdup(ca);
	}
      else if (ca && !mfi->album_artist)
	{
	  mfi->album_artist = strdup(ca);
	}
      else if (!ca && !mfi->album_artist)
	{
	  mfi->album_artist = strdup("");
	  mfi->album_artist_sort = strdup("");
	}
    }
  else if (mfi->media_kind == MEDIA_KIND_PODCAST) /* Podcast */
    {
      if (mfi->album_artist)
	free(mfi->album_artist);
      mfi->album_artist = strdup("");
      mfi->album_artist_sort = strdup("");
    }
  else if (!mfi->album_artist)   /* Regular media without album_artist */
    {
      mfi->album_artist = strdup(mfi->artist);
    }

  if (!mfi->album_artist_sort && (strcmp(mfi->album_artist, mfi->artist) == 0))
    mfi->album_artist_sort = strdup(mfi->artist_sort);
  else
    sort_tag_create(&mfi->album_artist_sort, mfi->album_artist);

  /* Composer is not one of our mandatory tags, so take extra care */
  if (mfi->composer_sort || mfi->composer)
    sort_tag_create(&mfi->composer_sort, mfi->composer);
}
int
configuration(struct app_parent *app_p,
              const char *configfile,
              char **policy_file,
              char **syslog_ident,
              int *syslog_flags,
              int *syslog_facility) {
    unsigned int i, j;
    struct tq_listener_s *p_listener = NULL;
    struct tq_service_s *p_service = NULL;
    char *buf = NULL;
    cfg_t *cfg;
    cfg_t *syslog_sec;
    unsigned n_listener, n_services;
    int ret;
    static cfg_opt_t syslog_opts[] = {
        CFG_STR("ident", NULL, CFGF_NONE),
        CFG_INT_CB("facility", NONE, CFGF_NONE, &cb_syslog_facility),
        CFG_INT_LIST_CB("options", NULL, CFGF_NONE, &cb_syslog_options),
        CFG_END()
    };
    static cfg_opt_t service_opts[] = {
        CFG_INT_CB("type", NONE, CFGF_NONE, &cb_service_type),
        CFG_STR("uri", 0, CFGF_NONE),
        CFG_INT("threads", 4, CFGF_NONE),
        CFG_END()
    };
    static cfg_opt_t listener_opts[] = {
        CFG_STR("bindaddress", 0, CFGF_NONE),
        CFG_INT("port", 9001, CFGF_NONE),
        CFG_INT("backlog", 1024, CFGF_NONE),
        CFG_STR("cert", 0, CFGF_NONE),
        CFG_STR("key", 0, CFGF_NONE),
        CFG_STR("cafile", 0, CFGF_NONE),
        CFG_STR("capath", 0, CFGF_NONE),
        CFG_STR("crlpath", 0, CFGF_NONE),
        CFG_STR("password", 0, CFGF_NONE),
        CFG_STR("cipherlist", 0, CFGF_NONE),
        CFG_INT_CB("clientauth", NONE, CFGF_NONE, &cb_answer),
        CFG_INT_CB("rfc3820", NONE, CFGF_NONE, &cb_answer),
        CFG_STR("whitelist", 0, CFGF_NONE),
        CFG_STR("blacklist", 0, CFGF_NONE),
        CFG_SEC("service", service_opts, CFGF_MULTI),
        CFG_END()
    };
    cfg_opt_t opts[] = {
        CFG_INT_CB("debug", NONE, CFGF_NONE, &cb_answer),
        CFG_STR("policyfile", 0, CFGF_NONE),
        CFG_SEC("syslog", syslog_opts, CFGF_NONE),
        CFG_SEC("listener", listener_opts, CFGF_MULTI),
        CFG_END()
    };

    cfg = cfg_init(opts, CFGF_NOCASE);

    /* set a validating callback function for bookmark sections */
    /* cfg_set_validate_func(cfg, "bookmark", &cb_validate_bookmark); */

    ret = cfg_parse(cfg, configfile);
    if (ret == CFG_FILE_ERROR) {
        fprintf(stderr, "Error: could not open or read the configuration file "
               "\"%s\".\n", configfile);
        return GA_BAD;
    } else if (ret == CFG_PARSE_ERROR) {
        fprintf(stderr, "Error: parse error in the configuration file "
               "\"%s\".\n", configfile);
        return GA_BAD;
    }

    /* Generic */
    app_p->debug = cfg_getint(cfg, "debug");
    if (app_p->debug == MAYBE || app_p->debug == OPTIONAL) {
        printf("Overriding debug setting to 'yes'\n");
        app_p->debug = YES;
    } else if (app_p->debug == YES) {
        printf("= Service running in DEBUG mode =\n");
    }

    /* XACML Rules file */
    *policy_file = strdup(cfg_getstr(cfg, "policyfile"));
    if (*policy_file == NULL) {
        fprintf(stderr, "Error: no \"policyfile\" set in the configuration file\n");
        return GA_BAD;
    } else {
        if (app_p->verbose) {
            printf("Using XACML Policy file: \"%s\"\n", *policy_file);
        }
    }

    /* Syslog */
    syslog_sec = cfg_getsec(cfg, "syslog");
    if (syslog_sec == NULL) {
        fprintf(stderr, "Error: no \"syslog\" section found in the "
                        "configuration file \"%s\"\n", configfile);
    } else {
        *syslog_ident = strdup(cfg_getstr(syslog_sec, "ident"));
        *syslog_facility = cfg_getint(syslog_sec, "facility");

        if (app_p->debug == YES) {
            printf("found syslog\n");
            printf("    ident = %s\n", cfg_getstr(syslog_sec, "ident"));
            printf("    facility = %ld\n", cfg_getint(syslog_sec, "facility"));
            printf("BUG\n");

            for (i = 0; i < cfg_size(syslog_sec, "options"); i++) {
                printf("options[%d] == %ld\n", i, cfg_getnint(syslog_sec, "options", i));
            }
            printf("BUG\n");
        }

        /* Hardwired the settings */
        *syslog_flags = LOG_PID|LOG_NDELAY;

        if (app_p->verbose > 1) {
            *syslog_flags |= LOG_PERROR;
        }
    }

    /* Listeners */
    n_listener = cfg_size(cfg, "listener");
    if (app_p->verbose) {
        printf("%d configured listeners:\n", n_listener);
    }
    for (i = 0; i < n_listener; i++) {
        cfg_t *ls = cfg_getnsec(cfg, "listener", i);
        if (ls == NULL) {
            goto cleanup;
        }

        p_listener = malloc(sizeof(struct tq_listener_s));
        if (p_listener == NULL) {
            fprintf(stderr, "Error: memory allocation problem, couldn't allocate %lu bytes\n",
                    sizeof(struct tq_listener_s));
            goto cleanup;
        }
        memset(p_listener, 0, sizeof(struct tq_listener_s));
        TAILQ_INIT(&(p_listener->services_head));

        /* Settings */
        STRDUP_OR_GOTO_CLEANUP(p_listener->bindip,          cfg_getstr(ls, "bindaddress"));
        p_listener->port                           = (short)cfg_getint(ls, "port");
        p_listener->backlog                        = (short)cfg_getint(ls, "backlog");
        STRDUP_OR_GOTO_CLEANUP(p_listener->cert,            cfg_getstr(ls, "cert"));
        STRDUP_OR_GOTO_CLEANUP(p_listener->key,             cfg_getstr(ls, "key"));
        STRDUP_OR_GOTO_CLEANUP(p_listener->cafile,          cfg_getstr(ls, "cafile"));
        STRDUP_OR_GOTO_CLEANUP(p_listener->capath,          cfg_getstr(ls, "capath"));
        STRDUP_OR_GOTO_CLEANUP(p_listener->crlpath,         cfg_getstr(ls, "crlpath"));
        STRDUP_OR_GOTO_CLEANUP(p_listener->cipherlist,      cfg_getstr(ls, "cipherlist") ?
                                                                cfg_getstr(ls, "cipherlist") :
                                                                "HIGH");
        STRDUP_OR_GOTO_CLEANUP(p_listener->cert_password,   cfg_getstr(ls, "password"));
        STRDUP_OR_GOTO_CLEANUP(p_listener->whitelist_path,  cfg_getstr(ls, "whitelist"));
        STRDUP_OR_GOTO_CLEANUP(p_listener->blacklist_path,  cfg_getstr(ls, "blacklist"));
        p_listener->clientauth                     = (short)cfg_getint(ls, "clientauth");
        p_listener->rfc3820                        = (short)cfg_getint(ls, "rfc3820");

        /* Normalizer */
        if (p_listener->clientauth == MAYBE)
            p_listener->clientauth = OPTIONAL;
        if (p_listener->rfc3820 == MAYBE || p_listener->rfc3820 == OPTIONAL)
            p_listener->rfc3820 = YES;

        /* Create evhtp_ssl_cfg_t */
        if (create_evhtp_ssl_cfg_from_tq_listener(p_listener) == GA_BAD) {
            goto cleanup;
        }


        /* Services per listener */
        n_services = cfg_size(ls, "service");
        if (app_p->verbose) {
            printf("      %d\n", n_services);
        }
        for (j = 0; j < n_services; j++) {
            cfg_t *serv = cfg_getnsec(ls, "service", j);
            if (serv == NULL) {
                goto cleanup;
            }

            p_service = malloc(sizeof(struct tq_service_s));
            if (p_service == NULL) {
                fprintf(stderr, "Error: memory allocation problem, couldn't allocate %lu bytes\n",
                        sizeof(struct tq_service_s));
                goto cleanup;
            }
            memset(p_service, 0, sizeof(struct tq_service_s));

            p_service->parent_listener = p_listener;

            /* Thread count override in Debug mode - max is 1 worker thread */
            if (app_p->debug == YES) {
                p_service->thread_cnt = 1;
            } else {
                p_service->thread_cnt = (short)cfg_getint(serv, "threads");
            }

            p_service->ltype = cfg_getint(serv, "type");
            p_service->uri = cfg_getstr(serv, "uri");
            if (p_service->uri && p_service->uri[0] == '/') {
                p_service->uri = strdup(p_service->uri);
            } else {
                buf = malloc(strlen(p_service->uri) + 2);
                if (buf == NULL) {
                    goto cleanup;
                }
                snprintf(buf, strlen(p_service->uri) + 2, "/%s", p_service->uri);
                p_service->uri = buf;
            }
            if (app_p->verbose) {
                printf("       uri = %s\n", p_service->uri);
                printf("       type = %s\n", p_service->ltype == PDP ? "PDP" : p_service->ltype == PAP ? "PAP" : p_service->ltype == PEP ? "PEP" : "unknown");
            }

            TAILQ_INSERT_TAIL(&(p_listener->services_head), p_service, next);
        }

        TAILQ_INSERT_TAIL(&(app_p->listener_head), p_listener, next);
    }

    cfg_free(cfg);
    return GA_GOOD;
cleanup:
    cfg_free(cfg);
    return GA_BAD;

}
Beispiel #25
0
/* Thread: main */
int
httpd_init(void)
{
  unsigned short port;
  int v6enabled;
  int ret;

  httpd_exit = 0;

  v6enabled = cfg_getbool(cfg_getsec(cfg, "general"), "ipv6");

  evbase_httpd = event_base_new();
  if (!evbase_httpd)
    {
      DPRINTF(E_FATAL, L_HTTPD, "Could not create an event base\n");

      return -1;
    }

  ret = rsp_init();
  if (ret < 0)
    {
      DPRINTF(E_FATAL, L_HTTPD, "RSP protocol init failed\n");

      goto rsp_fail;
    }

  ret = daap_init();
  if (ret < 0)
    {
      DPRINTF(E_FATAL, L_HTTPD, "DAAP protocol init failed\n");

      goto daap_fail;
    }

  ret = dacp_init();
  if (ret < 0)
    {
      DPRINTF(E_FATAL, L_HTTPD, "DACP protocol init failed\n");

      goto dacp_fail;
    }

#ifdef USE_EVENTFD
  exit_efd = eventfd(0, EFD_CLOEXEC);
  if (exit_efd < 0)
    {
      DPRINTF(E_FATAL, L_HTTPD, "Could not create eventfd: %s\n", strerror(errno));

      goto pipe_fail;
    }
#else
# if defined(__linux__)
  ret = pipe2(exit_pipe, O_CLOEXEC);
# else
  ret = pipe(exit_pipe);
# endif
  if (ret < 0)
    {
      DPRINTF(E_FATAL, L_HTTPD, "Could not create pipe: %s\n", strerror(errno));

      goto pipe_fail;
    }
#endif /* USE_EVENTFD */

#ifdef USE_EVENTFD
  event_set(&exitev, exit_efd, EV_READ, exit_cb, NULL);
#else
  event_set(&exitev, exit_pipe[0], EV_READ, exit_cb, NULL);
#endif
  event_base_set(evbase_httpd, &exitev);
  event_add(&exitev, NULL);

  evhttpd = evhttp_new(evbase_httpd);
  if (!evhttpd)
    {
      DPRINTF(E_FATAL, L_HTTPD, "Could not create HTTP server\n");

      goto evhttp_fail;
    }

  port = cfg_getint(cfg_getsec(cfg, "library"), "port");

  /* We are binding v6 and v4 separately, and we allow v6 to fail
   * as IPv6 might not be supported on the system.
   * We still warn about the failure, in case there's another issue.
   */
  ret = evhttp_bind_socket(evhttpd, "0.0.0.0", port);
  if (ret < 0)
    {
      DPRINTF(E_FATAL, L_HTTPD, "Could not bind INADDR_ANY:%d\n", port);

      goto bind_fail;
    }

  if (v6enabled)
    {
      ret = evhttp_bind_socket(evhttpd, "::", port);
      if (ret < 0)
	DPRINTF(E_WARN, L_HTTPD, "Could not bind IN6ADDR_ANY:%d (that's OK)\n", port);
    }

  evhttp_set_gencb(evhttpd, httpd_gen_cb, NULL);

  ret = pthread_create(&tid_httpd, NULL, httpd, NULL);
  if (ret != 0)
    {
      DPRINTF(E_FATAL, L_HTTPD, "Could not spawn HTTPd thread: %s\n", strerror(errno));

      goto thread_fail;
    }

  return 0;

 thread_fail:
 bind_fail:
  evhttp_free(evhttpd);
 evhttp_fail:
#ifdef USE_EVENTFD
  close(exit_efd);
#else
  close(exit_pipe[0]);
  close(exit_pipe[1]);
#endif
 pipe_fail:
  dacp_deinit();
 dacp_fail:
  daap_deinit();
 daap_fail:
  rsp_deinit();
 rsp_fail:
  event_base_free(evbase_httpd);

  return -1;
}
Beispiel #26
0
int main(int argc, char *argv[])
{
	struct stat sb; // To check if config file exist.
	struct in_addr iaddrf, iaddrl;      // To validate IP addresses
    struct in6_addr i6addrf;   			// also
    cfg_t *cfg, *cfg_ipv4, *cfg_ipv6;
	const char *sect_name;
	char *addr_first, *addr_last;
    unsigned char addr_maskbits;
    int port_first, port_last;
    char which[sizeof("ABC")];
    
    struct config_struct cs;

	struct nl_sock *nls;
	int ret;

	if (argc != 2)
	{
		printf("Usage: %s <config-file>\n", argv[0]);
		exit(EXIT_FAILURE);
	}
	if ( stat(argv[1], &sb) == -1 )
	{
		printf("Error: Can not open configuration file: %s\n", argv[1]);
		exit(EXIT_FAILURE);
	}

    cfg_opt_t ipv4_opts[] =
    {
        CFG_STR("ipv4_addr_net", IPV4_DEF_NET, CFGF_NONE), 
        CFG_INT("ipv4_addr_net_mask_bits", IPV4_DEF_MASKBITS, CFGF_NONE), 
        CFG_STR("ipv4_pool_range_first", IPV4_DEF_POOL_FIRST, CFGF_NONE), 
        CFG_STR("ipv4_pool_range_last", IPV4_DEF_POOL_LAST, CFGF_NONE), 
        CFG_INT("ipv4_tcp_port_range_first", IPV4_DEF_TCP_POOL_FIRST, CFGF_NONE), 
        CFG_INT("ipv4_tcp_port_range_last", IPV4_DEF_TCP_POOL_LAST, CFGF_NONE), 
        CFG_INT("ipv4_udp_port_range_first", IPV4_DEF_UDP_POOL_FIRST, CFGF_NONE), 
        CFG_INT("ipv4_udp_port_range_last", IPV4_DEF_UDP_POOL_LAST, CFGF_NONE), 
        CFG_END()
    };
	cfg_opt_t ipv6_opts[] =
    {
        CFG_STR("ipv6_net_prefix", IPV6_DEF_PREFIX, CFGF_NONE), 
        CFG_INT("ipv6_net_mask_bits", IPV6_DEF_MASKBITS, CFGF_NONE), 
        CFG_INT("ipv6_tcp_port_range_first", IPV6_DEF_TCP_POOL_FIRST, CFGF_NONE), 
        CFG_INT("ipv6_tcp_port_range_last", IPV6_DEF_TCP_POOL_LAST, CFGF_NONE), 
        CFG_INT("ipv6_udp_port_range_first", IPV6_DEF_UDP_POOL_FIRST, CFGF_NONE), 
        CFG_INT("ipv6_udp_port_range_last", IPV6_DEF_UDP_POOL_LAST, CFGF_NONE), 
		CFG_END()
    };
    cfg_opt_t opts[] =
    {
        CFG_SEC("ipv4", ipv4_opts, CFGF_NONE),
        CFG_SEC("ipv6", ipv6_opts, CFGF_NONE),
        CFG_END()
    };

    cfg = cfg_init(opts, CFGF_NONE);
    if(cfg_parse(cfg, argv[1]) == CFG_PARSE_ERROR)
	{
		printf("Error parsing configuration file: %s\n", argv[1]);
        exit_error_conf(cfg);
	}

	/* Loading IPv4 configuration */
	{
        cfg_ipv4 = cfg_getsec(cfg, "ipv4");

		sect_name = cfg_name(cfg_ipv4);
		printf ("Section: %s\n", sect_name);

		addr_first = cfg_getstr(cfg_ipv4, "ipv4_addr_net");
        if ( inet_aton(addr_first, &iaddrf) == 0 )	// Validate ipv4 addr
		{
			printf("Error: Invalid IPv4 address net: %s\n", addr_first);
			exit_error_conf(cfg);
		}
        addr_maskbits = cfg_getint(cfg_ipv4, "ipv4_addr_net_mask_bits");
        if (addr_maskbits > 32 || addr_maskbits < 0)
        {
            printf("Error: Bad IPv4 network mask bits value: %d\n", addr_maskbits);
			exit_error_conf(cfg);
        }
		cs.ipv4_addr_net = iaddrf;
        cs.ipv4_addr_net_mask_bits = addr_maskbits;
		printf("\tPool Network: %s/%d\n", addr_first, addr_maskbits);
		//
		addr_first = cfg_getstr(cfg_ipv4, "ipv4_pool_range_first");
        addr_last = cfg_getstr(cfg_ipv4, "ipv4_pool_range_last");
		if ( inet_aton(addr_first, &iaddrf) == 0 )	// Validate ipv4 addr
		{
			printf("Error: Malformed ipv4_pool_range_first: %s\n", addr_first);
			exit_error_conf(cfg);
		}
		if ( inet_aton(addr_last, &iaddrl) == 0 )	// Validate ipv4 addr
		{
			printf("Error: Malformed ipv4_pool_range_last: %s\n", addr_last);
			exit_error_conf(cfg);
		}
		if (iaddrf.s_addr > iaddrl.s_addr)	// Validate that: first < last
		{
			printf("Error: First pool address is greater than last pool address.\n");
			exit_error_conf(cfg);
		}
        cs.ipv4_pool_range_first = iaddrf;
        cs.ipv4_pool_range_last = iaddrl;
		printf("\t\t- First address: %s\n", inet_ntoa(iaddrf));
		printf("\t\t- Last address: %s\n", inet_ntoa(iaddrl));
        //
        port_first = cfg_getint(cfg_ipv4, "ipv4_tcp_port_range_first");
        port_last = cfg_getint(cfg_ipv4, "ipv4_tcp_port_range_last");
        sprintf(which, "TCP");
        if (port_first < 0 || port_first > 65535)
        {
            printf("Error: Invalid first %s port: %d\n", which, port_first);
            exit_error_conf(cfg);
        }
        if (port_last < 0 || port_last > 65535)
        {
            printf("Error: Invalid last %s port: %d\n", which, port_last);
            exit_error_conf(cfg);
        }
        if (port_first > port_last)
        {
            printf("Error: First %s port is greater than last port.\n", which);
            exit_error_conf(cfg);
        }
        cs.ipv4_tcp_port_first = port_first;
        cs.ipv4_tcp_port_last = port_last;
		printf("\t%s pool port range: %d-%d\n", which, port_first, port_last);
		//
        port_first = cfg_getint(cfg_ipv4, "ipv4_udp_port_range_first");
        port_last = cfg_getint(cfg_ipv4, "ipv4_udp_port_range_last");
        sprintf(which, "UDP");
        if (port_first < 0 || port_first > 65535)
        {
            printf("Error: Invalid first %s port: %d\n", which, port_first);
            exit_error_conf(cfg);
        }
        if (port_last < 0 || port_last > 65535)
        {
            printf("Error: Invalid last %s port: %d\n", which, port_last);
            exit_error_conf(cfg);
        }
        if (port_first > port_last)
        {
            printf("Error: First %s port is greater than last port.\n", which);
            exit_error_conf(cfg);
        }
        cs.ipv4_udp_port_first = port_first;
        cs.ipv4_udp_port_last = port_last;
		printf("\t%s pool port range: %d-%d\n", which, port_first, port_last);
        
		printf ("\n" );
    }
	
    /* Loading IPv6 configuration */
	{
        cfg_ipv6 = cfg_getsec(cfg, "ipv6");

		sect_name = cfg_name(cfg_ipv6);
        
		printf ("Section: %s\n", sect_name );
		addr_first = cfg_getstr(cfg_ipv6, "ipv6_net_prefix");
        
        if ( inet_pton(AF_INET6, addr_first, &i6addrf) < 1 )	// Validate ipv6 addr
		{
			printf("Error: Invalid IPv6 address net: %s\n", addr_first);
			exit_error_conf(cfg);
		}
        addr_maskbits = cfg_getint(cfg_ipv6, "ipv6_net_mask_bits");
        if (addr_maskbits > 128 || addr_maskbits < 0)
        {
            printf("Error: Bad IPv6 network mask bits value: %d\n", addr_maskbits);
			exit_error_conf(cfg);
        }
		cs.ipv6_net_prefix = i6addrf;
        cs.ipv6_net_mask_bits = addr_maskbits;
		printf("\tPrefix: %s/%d\n", addr_first, addr_maskbits);
        //
        port_first = cfg_getint(cfg_ipv6, "ipv6_tcp_port_range_first");
        port_last = cfg_getint(cfg_ipv6, "ipv6_tcp_port_range_last");
        sprintf(which, "TCP");
        if (port_first < 0 || port_first > 65535)
        {
            printf("Error: Invalid first %s port: %d\n", which, port_first);
            exit_error_conf(cfg);
        }
        if (port_last < 0 || port_last > 65535)
        {
            printf("Error: Invalid last %s port: %d\n", which, port_last);
            exit_error_conf(cfg);
        }
        if (port_first > port_last)
        {
            printf("Error: First %s port is greater than last port.\n", which);
            exit_error_conf(cfg);
        }
        cs.ipv6_tcp_port_range_first = port_first;
        cs.ipv6_tcp_port_range_last = port_last;
		printf("\t%s pool port range: %d-%d\n", which, port_first, port_last);
		//
        port_first = cfg_getint(cfg_ipv6, "ipv6_udp_port_range_first");
        port_last = cfg_getint(cfg_ipv6, "ipv6_udp_port_range_last");
        sprintf(which, "UDP");
        if (port_first < 0 || port_first > 65535)
        {
            printf("Error: Invalid first %s port: %d\n", which, port_first);
            exit_error_conf(cfg);
        }
        if (port_last < 0 || port_last > 65535)
        {
            printf("Error: Invalid last %s port: %d\n", which, port_last);
            exit_error_conf(cfg);
        }
        if (port_first > port_last)
        {
            printf("Error: First %s port is greater than last port.\n", which);
            exit_error_conf(cfg);
        }
        cs.ipv6_udp_port_range_first = port_first;
        cs.ipv6_udp_port_range_last = port_last;
		printf("\t%s pool port range: %d-%d\n", which, port_first, port_last);
        
		printf ("\n" );
    }

	cfg_free(cfg);

    /* We got the configuration structure, now send it to the module
     * using netlink sockets. */

    // Reserve memory for netlink socket
    nls = nl_socket_alloc();
    if (!nls) {
        printf("bad nl_socket_alloc\n");
        return EXIT_FAILURE;
    }

	// Bind and connect the socket to a protocol
    ret = nl_connect(nls, NETLINK_USERSOCK);
    if (ret < 0) {
        nl_perror(ret, "nl_connect");
        nl_socket_free(nls);
        return EXIT_FAILURE;
    }

    ret = nl_send_simple(nls, MY_MSG_TYPE, 0, &(cs), sizeof(cs));
    if (ret < 0) {
        nl_perror(ret, "nl_send_simple");
        printf("Error sending message, is module loaded?\n");
        nl_close(nls);
        nl_socket_free(nls);
        return EXIT_FAILURE;
    } else {        
	    printf("Message sent (%d bytes):\n", ret);
        //print_nat64_run_conf(nrc);
    }
		

    nl_close(nls);
    nl_socket_free(nls);
    
    exit(EXIT_SUCCESS);
}
Beispiel #27
0
int
configure_rtr(cfg_t *cfg)
{
    lisp_xtr_t *xtr;
    shash_t *lcaf_ht;
    mapping_t *mapping;
    map_local_entry_t *map_loc_e;
    void *fwd_map_inf;
    int n,i;

    /* CREATE AND CONFIGURE RTR (xTR in fact) */
    if (ctrl_dev_create(RTR_MODE, &ctrl_dev) != GOOD) {
        OOR_LOG(LCRIT, "Failed to create RTR. Aborting!");
        return (BAD);
    }

    lcaf_ht = parse_lcafs(cfg);

    xtr = CONTAINER_OF(ctrl_dev, lisp_xtr_t, super);
    if (configure_tunnel_router(cfg, xtr, lcaf_ht)!=GOOD){
        return (BAD);
    }

    /* INTERFACES CONFIG */
    n = cfg_size(cfg, "rtr-ifaces");
    if (n) {
        cfg_t *rifs = cfg_getsec(cfg, "rtr-ifaces");
        int nr = cfg_size(rifs, "rtr-iface");
        for(i = 0; i < nr; i++) {
            cfg_t *ri = cfg_getnsec(rifs, "rtr-iface", i);
            if (add_rtr_iface(xtr,
                    cfg_getstr(ri, "iface"),
                    cfg_getint(ri, "ip_version"),
                    cfg_getint(ri, "priority"),
                    cfg_getint(ri, "weight")) == GOOD) {
                OOR_LOG(LDBG_1, "Configured interface %s for RTR",
                        cfg_getstr(ri, "iface"));
            } else{
                OOR_LOG(LERR, "Can't configure iface %s for RTR",
                        cfg_getstr(ri, "iface"));
            }
        }
    }

    /* RTR DATABASE MAPPINGS (like for instance replication lists) */
    n = cfg_size(cfg, "rtr-database-mapping");
    for (i = 0; i < n; i++) {
        mapping = parse_mapping(cfg_getnsec(cfg, "rtr-database-mapping",i),&(xtr->super),lcaf_ht,TRUE);
        if (mapping == NULL){
            continue;
        }
        map_loc_e = map_local_entry_new_init(mapping);
        if (map_loc_e == NULL){
            mapping_del(mapping);
            continue;
        }

        fwd_map_inf = xtr->fwd_policy->new_map_loc_policy_inf(xtr->fwd_policy_dev_parm,mapping,NULL);
        if (fwd_map_inf == NULL){
            OOR_LOG(LERR, "Couldn't create forward information for rtr database mapping with EID: %s. Discarding it...",
                    lisp_addr_to_char(mapping_eid(mapping)));
            map_local_entry_del(map_loc_e);
            continue;
        }
        map_local_entry_set_fwd_info(map_loc_e, fwd_map_inf, xtr->fwd_policy->del_map_loc_policy_inf);

        if (add_local_db_map_local_entry(map_loc_e,xtr) != GOOD){
            map_local_entry_del(map_loc_e);
            continue;
        }


        if (add_local_db_map_local_entry(map_loc_e,xtr) != GOOD){
            map_local_entry_del(map_loc_e);
        }
    }

    /* Deallocate PiTRs and PeTRs elements */
    glist_destroy(xtr->pitrs);
    xtr->pitrs = NULL;

    shash_destroy(lcaf_ht);

    return(GOOD);
}
Beispiel #28
0
int
main(int argc, char **argv)
{
  int option;
  char *configfile;
  int background;
  int mdns_no_rsp;
  int mdns_no_daap;
  int loglevel;
  char *logdomains;
  char *logfile;
  char *ffid;
  char *pidfile;
  const char *gcry_version;
  sigset_t sigs;
  int sigfd;
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
  struct kevent ke_sigs[4];
#endif
  int ret;

  struct option option_map[] =
    {
      { "ffid",         1, NULL, 'b' },
      { "debug",        1, NULL, 'd' },
      { "logdomains",   1, NULL, 'D' },
      { "foreground",   0, NULL, 'f' },
      { "config",       1, NULL, 'c' },
      { "pidfile",      1, NULL, 'P' },
      { "version",      0, NULL, 'v' },

      { "mdns-no-rsp",  0, NULL, 512 },
      { "mdns-no-daap", 0, NULL, 513 },

      { NULL,           0, NULL, 0 }
    };

  configfile = CONFFILE;
  pidfile = PIDFILE;
  loglevel = -1;
  logdomains = NULL;
  logfile = NULL;
  background = 1;
  ffid = NULL;
  mdns_no_rsp = 0;
  mdns_no_daap = 0;

  while ((option = getopt_long(argc, argv, "D:d:c:P:fb:v", option_map, NULL)) != -1)
    {
      switch (option)
	{
	  case 512:
	    mdns_no_rsp = 1;
	    break;

	  case 513:
	    mdns_no_daap = 1;
	    break;

	  case 'b':
            ffid = optarg;
            break;

	  case 'd':
	    ret = safe_atoi32(optarg, &option);
	    if (ret < 0)
	      fprintf(stderr, "Error: loglevel must be an integer in '-d %s'\n", optarg);
	    else
	      loglevel = option;
            break;

	  case 'D':
	    logdomains = optarg;
            break;

          case 'f':
            background = 0;
            break;

          case 'c':
            configfile = optarg;
            break;

          case 'P':
	    pidfile = optarg;
            break;

          case 'v':
	    version();
            return EXIT_SUCCESS;
            break;

          default:
            usage(argv[0]);
            return EXIT_FAILURE;
            break;
        }
    }

  ret = logger_init(NULL, NULL, (loglevel < 0) ? E_LOG : loglevel);
  if (ret != 0)
    {
      fprintf(stderr, "Could not initialize log facility\n");

      return EXIT_FAILURE;
    }

  ret = conffile_load(configfile);
  if (ret != 0)
    {
      DPRINTF(E_FATAL, L_MAIN, "Config file errors; please fix your config\n");

      logger_deinit();
      return EXIT_FAILURE;
    }

  logger_deinit();

  /* Reinit log facility with configfile values */
  if (loglevel < 0)
    loglevel = cfg_getint(cfg_getsec(cfg, "general"), "loglevel");

  logfile = cfg_getstr(cfg_getsec(cfg, "general"), "logfile");

  ret = logger_init(logfile, logdomains, loglevel);
  if (ret != 0)
    {
      fprintf(stderr, "Could not reinitialize log facility with config file settings\n");

      conffile_unload();
      return EXIT_FAILURE;
    }

  /* Set up libevent logging callback */
  event_set_log_callback(logger_libevent);

  DPRINTF(E_LOG, L_MAIN, "Forked Media Server Version %s taking off\n", VERSION);

  ret = av_lockmgr_register(ffmpeg_lockmgr);
  if (ret < 0)
    {
      DPRINTF(E_FATAL, L_MAIN, "Could not register ffmpeg lock manager callback\n");

      ret = EXIT_FAILURE;
      goto ffmpeg_init_fail;
    }

  av_register_all();
#if LIBAVFORMAT_VERSION_MAJOR >= 54 || (LIBAVFORMAT_VERSION_MAJOR == 53 && LIBAVFORMAT_VERSION_MINOR >= 13)
  avformat_network_init();
#endif
  av_log_set_callback(logger_ffmpeg);

#ifdef LASTFM
  /* Initialize libcurl */
  curl_global_init(CURL_GLOBAL_DEFAULT);
#endif

  /* Initialize libgcrypt */
  gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);

  gcry_version = gcry_check_version(GCRYPT_VERSION);
  if (!gcry_version)
    {
      DPRINTF(E_FATAL, L_MAIN, "libgcrypt version mismatch\n");

      ret = EXIT_FAILURE;
      goto gcrypt_init_fail;
    }

  /* We aren't handling anything sensitive, so give up on secure
   * memory, which is a scarce system resource.
   */
  gcry_control(GCRYCTL_DISABLE_SECMEM, 0);

  gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);

  DPRINTF(E_DBG, L_MAIN, "Initialized with gcrypt %s\n", gcry_version);

  /* Block signals for all threads except the main one */
  sigemptyset(&sigs);
  sigaddset(&sigs, SIGINT);
  sigaddset(&sigs, SIGHUP);
  sigaddset(&sigs, SIGCHLD);
  sigaddset(&sigs, SIGTERM);
  sigaddset(&sigs, SIGPIPE);
  ret = pthread_sigmask(SIG_BLOCK, &sigs, NULL);
  if (ret != 0)
    {
      DPRINTF(E_LOG, L_MAIN, "Error setting signal set\n");

      ret = EXIT_FAILURE;
      goto signal_block_fail;
    }

  /* Daemonize and drop privileges */
  ret = daemonize(background, pidfile);
  if (ret < 0)
    {
      DPRINTF(E_LOG, L_MAIN, "Could not initialize server\n");

      ret = EXIT_FAILURE;
      goto daemon_fail;
    }

  /* Initialize libevent (after forking) */
  evbase_main = event_init();

  DPRINTF(E_LOG, L_MAIN, "mDNS init\n");
  ret = mdns_init();
  if (ret != 0)
    {
      DPRINTF(E_FATAL, L_MAIN, "mDNS init failed\n");

      ret = EXIT_FAILURE;
      goto mdns_fail;
    }

  /* Initialize the database before starting */
  DPRINTF(E_INFO, L_MAIN, "Initializing database\n");
  ret = db_init();
  if (ret < 0)
    {
      DPRINTF(E_FATAL, L_MAIN, "Database init failed\n");

      ret = EXIT_FAILURE;
      goto db_fail;
    }

  /* Open a DB connection for the main thread */
  ret = db_perthread_init();
  if (ret < 0)
    {
      DPRINTF(E_FATAL, L_MAIN, "Could not perform perthread DB init for main\n");

      ret = EXIT_FAILURE;
      goto db_fail;
    }

  /* Spawn worker thread */
  ret = worker_init();
  if (ret != 0)
    {
      DPRINTF(E_FATAL, L_MAIN, "Worker thread failed to start\n");

      ret = EXIT_FAILURE;
      goto worker_fail;
    }

  /* Spawn cache thread */
  ret = cache_init();
  if (ret != 0)
    {
      DPRINTF(E_FATAL, L_MAIN, "Cache thread failed to start\n");

      ret = EXIT_FAILURE;
      goto cache_fail;
    }

  /* Spawn file scanner thread */
  ret = filescanner_init();
  if (ret != 0)
    {
      DPRINTF(E_FATAL, L_MAIN, "File scanner thread failed to start\n");

      ret = EXIT_FAILURE;
      goto filescanner_fail;
    }

#ifdef HAVE_SPOTIFY_H
  /* Spawn Spotify thread */
  ret = spotify_init();
  if (ret < 0)
    {
      DPRINTF(E_INFO, L_MAIN, "Spotify thread not started\n");;
    }
#endif

  /* Spawn player thread */
  ret = player_init();
  if (ret != 0)
    {
      DPRINTF(E_FATAL, L_MAIN, "Player thread failed to start\n");

      ret = EXIT_FAILURE;
      goto player_fail;
    }

  /* Spawn HTTPd thread */
  ret = httpd_init();
  if (ret != 0)
    {
      DPRINTF(E_FATAL, L_MAIN, "HTTPd thread failed to start\n");

      ret = EXIT_FAILURE;
      goto httpd_fail;
    }

#ifdef MPD
  /* Spawn MPD thread */
  ret = mpd_init();
  if (ret != 0)
    {
      DPRINTF(E_FATAL, L_MAIN, "MPD thread failed to start\n");

      ret = EXIT_FAILURE;
      goto mpd_fail;
    }
#endif

  /* Start Remote pairing service */
  ret = remote_pairing_init();
  if (ret != 0)
    {
      DPRINTF(E_FATAL, L_MAIN, "Remote pairing service failed to start\n");

      ret = EXIT_FAILURE;
      goto remote_fail;
    }

  /* Register mDNS services */
  ret = register_services(ffid, mdns_no_rsp, mdns_no_daap);
  if (ret < 0)
    {
      ret = EXIT_FAILURE;
      goto mdns_reg_fail;
    }

#if defined(__linux__)
  /* Set up signal fd */
  sigfd = signalfd(-1, &sigs, SFD_NONBLOCK | SFD_CLOEXEC);
  if (sigfd < 0)
    {
      DPRINTF(E_FATAL, L_MAIN, "Could not setup signalfd: %s\n", strerror(errno));

      ret = EXIT_FAILURE;
      goto signalfd_fail;
    }

  event_set(&sig_event, sigfd, EV_READ, signal_signalfd_cb, NULL);

#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
  sigfd = kqueue();
  if (sigfd < 0)
    {
      DPRINTF(E_FATAL, L_MAIN, "Could not setup kqueue: %s\n", strerror(errno));

      ret = EXIT_FAILURE;
      goto signalfd_fail;
    }

  EV_SET(&ke_sigs[0], SIGINT, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
  EV_SET(&ke_sigs[1], SIGTERM, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
  EV_SET(&ke_sigs[2], SIGHUP, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
  EV_SET(&ke_sigs[3], SIGCHLD, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);

  ret = kevent(sigfd, ke_sigs, 4, NULL, 0, NULL);
  if (ret < 0)
    {
      DPRINTF(E_FATAL, L_MAIN, "Could not register signal events: %s\n", strerror(errno));

      ret = EXIT_FAILURE;
      goto signalfd_fail;
    }

  event_set(&sig_event, sigfd, EV_READ, signal_kqueue_cb, NULL);
#endif

  event_base_set(evbase_main, &sig_event);
  event_add(&sig_event, NULL);

  /* Run the loop */
  event_base_dispatch(evbase_main);

  DPRINTF(E_LOG, L_MAIN, "Stopping gracefully\n");
  ret = EXIT_SUCCESS;

  /*
   * On a clean shutdown, bring mDNS down first to give a chance
   * to the clients to perform a clean shutdown on their end
   */
  DPRINTF(E_LOG, L_MAIN, "mDNS deinit\n");
  mdns_deinit();

 signalfd_fail:
 mdns_reg_fail:
  DPRINTF(E_LOG, L_MAIN, "Remote pairing deinit\n");
  remote_pairing_deinit();

 remote_fail:
  DPRINTF(E_LOG, L_MAIN, "HTTPd deinit\n");
  httpd_deinit();

 httpd_fail:
  DPRINTF(E_LOG, L_MAIN, "TCPd deinit\n");
#ifdef MPD
  DPRINTF(E_LOG, L_MAIN, "MPD deinit\n");
  mpd_deinit();
 mpd_fail:
#endif

  DPRINTF(E_LOG, L_MAIN, "Player deinit\n");
  player_deinit();

 player_fail:
#ifdef HAVE_SPOTIFY_H
  DPRINTF(E_LOG, L_MAIN, "Spotify deinit\n");
  spotify_deinit();
#endif
  DPRINTF(E_LOG, L_MAIN, "File scanner deinit\n");
  filescanner_deinit();

 filescanner_fail:
  DPRINTF(E_LOG, L_MAIN, "Cache deinit\n");
  cache_deinit();

 cache_fail:
  DPRINTF(E_LOG, L_MAIN, "Worker deinit\n");
  worker_deinit();

 worker_fail:
  DPRINTF(E_LOG, L_MAIN, "Database deinit\n");
  db_perthread_deinit();
  db_deinit();

 db_fail:
  if (ret == EXIT_FAILURE)
    {
      DPRINTF(E_LOG, L_MAIN, "mDNS deinit\n");
      mdns_deinit();
    }

 mdns_fail:
 daemon_fail:
  if (background)
    {
      ret = seteuid(0);
      if (ret < 0)
	DPRINTF(E_LOG, L_MAIN, "seteuid() failed: %s\n", strerror(errno));
      else
	{
	  ret = unlink(pidfile);
	  if (ret < 0)
	    DPRINTF(E_LOG, L_MAIN, "Could not unlink PID file %s: %s\n", pidfile, strerror(errno));
	}
    }

 signal_block_fail:
 gcrypt_init_fail:
#ifdef LASTFM
  curl_global_cleanup();
#endif
#if LIBAVFORMAT_VERSION_MAJOR >= 54 || (LIBAVFORMAT_VERSION_MAJOR == 53 && LIBAVFORMAT_VERSION_MINOR >= 13)
  avformat_network_deinit();
#endif
  av_lockmgr_register(NULL);

 ffmpeg_init_fail:
  DPRINTF(E_LOG, L_MAIN, "Exiting.\n");
  conffile_unload();
  logger_deinit();

  return ret;
}
Beispiel #29
0
int
conffile_load(char *file)
{
  cfg_t *lib;
  struct passwd *pw;
  char *runas;
  int ret;

  cfg = cfg_init(toplvl_cfg, CFGF_NONE);

  ret = cfg_parse(cfg, file);

  if (ret == CFG_FILE_ERROR)
    {
      DPRINTF(E_FATAL, L_CONF, "Could not open config file %s\n", file);

      goto out_fail;
    }
  else if (ret == CFG_PARSE_ERROR)
    {
      DPRINTF(E_FATAL, L_CONF, "Parse error in config file %s\n", file);

      goto out_fail;
    }

  /* Resolve runas username */
  runas = cfg_getstr(cfg_getsec(cfg, "general"), "uid");
  pw = getpwnam(runas);
  if (!pw)
    {
      DPRINTF(E_FATAL, L_CONF, "Could not lookup user %s: %s\n", runas, strerror(errno));

      goto out_fail;
    }

  runas_uid = pw->pw_uid;
  runas_gid = pw->pw_gid;

  lib = cfg_getsec(cfg, "library");

  if (cfg_size(lib, "directories") == 0)
    {
      DPRINTF(E_FATAL, L_CONF, "No directories specified for library\n");

      goto out_fail;
    }

  /* Do keyword expansion on library names */
  ret = conffile_expand_libname(lib);
  if (ret != 0)
    {
      DPRINTF(E_FATAL, L_CONF, "Could not expand library name\n");

      goto out_fail;
    }

  return 0;

 out_fail:
  cfg_free(cfg);

  return -1;
}
static int
process_track_file(plist_t trk)
{
  struct media_file_info *mfi;
  char *location;
  char *path;
  char *string;
  uint64_t integer;
  char **strval;
  uint32_t *intval;
  char *chrval;
  uint8_t boolean;
  int mfi_id;
  int i;
  int ret;

  ret = get_dictval_string_from_key(trk, "Location", &location);
  if ((ret < 0) || !location)
    {
      DPRINTF(E_LOG, L_SCAN, "Track type File with no Location\n");
      return -1;
    }

  if (strncmp(location, "file://", strlen("file://")) != 0)
    {
      DPRINTF(E_LOG, L_SCAN, "Track type File, but Location does not start with 'file://': '%s'\n", location);
      free(location);
      return -1;
    }

  path = evhttp_decode_uri(location + strlen("file://"));
  free(location);

  mfi_id = mfi_id_find(path);
  if (mfi_id <= 0)
    {
      free(path);
      return -1;
    }

  free(path);

  if (!cfg_getbool(cfg_getsec(cfg, "library"), "itunes_overrides"))
    return mfi_id;

  /* Override our metadata with what's provided by iTunes */
  mfi = db_file_fetch_byid(mfi_id);
  if (!mfi)
    {
      DPRINTF(E_LOG, L_SCAN, "Could not retrieve file info for file id %d\n", mfi_id);

      return mfi_id;
    }

  for (i = 0; md_map[i].key != NULL; i++)
    {
      switch (md_map[i].type)
	{
	  case PLIST_UINT:
	    ret = get_dictval_int_from_key(trk, md_map[i].key, &integer);
	    if (ret < 0)
	      break;

	    intval = (uint32_t *) ((char *) mfi + md_map[i].offset);

	    *intval = (uint32_t)integer;
	    break;

	  case PLIST_STRING:
	    ret = get_dictval_string_from_key(trk, md_map[i].key, &string);
	    if (ret < 0)
	      break;

	    strval = (char **) ((char *) mfi + md_map[i].offset);

	    if (*strval)
	      free(*strval);

	    *strval = string;
	    break;

	  case PLIST_BOOLEAN:
	    ret = get_dictval_bool_from_key(trk, md_map[i].key, &boolean);
	    if (ret < 0)
	      break;

	    chrval = (char *) mfi + md_map[i].offset;

	    *chrval = boolean;
	    break;

	  case PLIST_DATE:
	    intval = (uint32_t *) ((char *) mfi + md_map[i].offset);

	    get_dictval_date_from_key(trk, md_map[i].key, intval);
	    break;

	  default:
	    DPRINTF(E_WARN, L_SCAN, "Unhandled metadata type %d\n", md_map[i].type);
	    break;
	}
    }

  /* Set media_kind to 4 (Podcast) if Podcast is true */
  ret = get_dictval_bool_from_key(trk, "Podcast", &boolean); 
  if ((ret == 0) && boolean)
    {
      mfi->media_kind = MEDIA_KIND_PODCAST;
    }

  /* Don't let album_artist set to "Unknown artist" if we've
   * filled artist from the iTunes data in the meantime
   */
  if (strcmp(mfi->album_artist, "Unknown artist") == 0)
    {
      free(mfi->album_artist);
      mfi->album_artist = strdup(mfi->artist);
    }

  db_file_update(mfi);

  free_mfi(mfi, 0);

  return mfi_id;
}