]> git.tuebingen.mpg.de Git - paraslash.git/commitdiff
Merge branch 'maint'
authorAndre Noll <maan@tuebingen.mpg.de>
Fri, 11 Aug 2017 12:05:09 +0000 (14:05 +0200)
committerAndre Noll <maan@tuebingen.mpg.de>
Fri, 11 Aug 2017 12:05:09 +0000 (14:05 +0200)
* maint:
  server: Perform hostname lookup in client process.
  server: Fix memory leak in com_check().

1  2 
mood.c
server.c

diff --combined mood.c
index 315ef0cbdc61b7de1a3bbbd8f8683d7ab81d9c81,196d80e2882756214da91f3ad663258debf68ef2..027a77d4db05bd33698f082ab8c11b03c26b1a06
--- 1/mood.c
--- 2/mood.c
+++ b/mood.c
@@@ -8,7 -8,6 +8,7 @@@
  
  #include <regex.h>
  #include <osl.h>
 +#include <lopsub.h>
  
  #include "para.h"
  #include "error.h"
@@@ -59,13 -58,15 +59,13 @@@ struct mood_item 
        struct list_head mood_item_node;
  };
  
 -/**
 - * Created from the mood definition by mood_open().
 +/*
 + * Created from the mood definition by \ref change_current_mood().
   *
   * When a mood is opened, each line of its definition is investigated, and a
 - * corresponding mood item is produced. Each mood line starts with \p accept,
 - * \p deny, or \p score which determines the type of the mood line.  For each
 - * such type a linked list is maintained whose entries are the mood items.
 - *
 - * \sa mood_item, mood_open().
 + * corresponding mood item is produced. Each mood line starts with accept,
 + * deny, or score which determines the type of the mood line. For each such
 + * type a linked list is maintained whose entries are the mood items.
   */
  struct mood {
        /** The name of this mood. */
@@@ -80,7 -81,7 +80,7 @@@
  
  /*
   * If current_mood is NULL then no mood is currently open. If
 - * current_mood->name is NULL, the dummy mood is currently open
 + * current_mood->name is NULL, the dummy mood is currently open.
   */
  static struct mood *current_mood;
  
@@@ -140,8 -141,8 +140,8 @@@ static bool get_item_score(struct mood_
  }
  
  /* returns 1 if row admissible, 0 if not, negative on errors */
 -static int compute_mood_score(const struct osl_row *aft_row, struct mood *m,
 -              long *result)
 +static int row_is_admissible(const struct osl_row *aft_row, struct mood *m,
 +              long *scorep)
  {
        struct mood_item *item;
        int ret;
        if (!m)
                return -E_NO_MOOD;
        ret = get_afsi_of_row(aft_row, &afsi);
 -      if (ret< 0)
 +      if (ret < 0)
                return ret;
        ret = get_afhi_of_row(aft_row, &afhi);
 -      if (ret< 0)
 +      if (ret < 0)
                return ret;
        ret = get_audio_file_path_of_row(aft_row, &path);
 -      if (ret< 0)
 +      if (ret < 0)
                return ret;
        /* reject audio file if it matches any entry in the deny list */
        list_for_each_entry(item, &m->deny_list, mood_item_node) {
        }
        if (score_arg_sum)
                score /= score_arg_sum;
 -      *result = score;
 +      *scorep = score;
        return 1;
  }
  
@@@ -257,6 -258,7 +257,6 @@@ struct mood_line_parser_data 
   * <score> is either an integer or "random" which assigns a random score to
   * all matching files
   */
 -
  static int parse_mood_line(char *mood_line, void *data)
  {
        struct mood_line_parser_data *mlpd = data;
@@@ -363,9 -365,7 +363,7 @@@ success
        ret = 1;
  out:
        free_argv(argv);
-       if (ret >= 0)
-               return ret;
-       if (mi) {
+       if (mi && (ret < 0 || !mlpd->m)) { /* mi was not added to any list */
                free(mi->parser_data);
                free(mi);
        }
@@@ -521,7 -521,9 +519,7 @@@ static int del_afs_statistics(const str
        return 1;
  }
  
 -/**
 - * Structure used during mood_open().
 - *
 +/*
   * At mood open time we determine the set of admissible files for the given
   * mood. The mood score of each admissible file is computed by adding up all
   * mood item scores. Next, we update the afs statistics and append a struct
   * the afs_statistics and the current time) to the mood score. Finally, all
   * audio files in the temporary array are added to the score table and the
   * array is freed.
 - *
 - * \sa mood_method, admissible_array.
   */
  struct admissible_file_info
  {
@@@ -565,7 -569,7 +563,7 @@@ static int add_if_admissible(struct osl
        int ret;
        long score = 0;
  
 -      ret = compute_mood_score(aft_row, aa->m, &score);
 +      ret = row_is_admissible(aft_row, aa->m, &score);
        if (ret <= 0)
                return ret;
        if (statistics.num >= aa->size) {
@@@ -624,8 -628,7 +622,8 @@@ _static_inline_ int64_t update_quadrati
        return old_qd + delta * (sigma - 2 * old_sum / n - delta / n);
  }
  
 -static int update_afs_statistics(struct afs_info *old_afsi, struct afs_info *new_afsi)
 +static int update_afs_statistics(struct afs_info *old_afsi,
 +              struct afs_info *new_afsi)
  {
        unsigned n;
        int ret = get_num_admissible_files(&n);
@@@ -673,7 -676,7 +671,7 @@@ static int delete_from_statistics_and_s
   *
   * \return Positive on success, negative on errors.
   *
 - * \sa score_delete().
 + * \sa \ref score_delete().
   */
  static int mood_delete_audio_file(const struct osl_row *aft_row)
  {
@@@ -712,7 -715,7 +710,7 @@@ static int mood_update_audio_file(cons
        if (ret < 0)
                return ret;
        was_admissible = ret;
 -      ret = compute_mood_score(aft_row, current_mood, &score);
 +      ret = row_is_admissible(aft_row, current_mood, &score);
        if (ret < 0)
                return ret;
        is_admissible = (ret > 0);
@@@ -776,7 -779,8 +774,7 @@@ static void log_statistics(void
  /**
   * Close the current mood.
   *
 - * Free all resources of the current mood which were allocated during
 - * mood_open().
 + * Frees all resources of the current mood.
   */
  void close_current_mood(void)
  {
   * \return Positive on success, negative on errors. Loading the dummy mood
   * always succeeds.
   *
 - * \sa struct admissible_file_info, struct admissible_array, struct
 - * afs_info::last_played, mood_close().
 + * \sa struct \ref afs_info::last_played.
   */
  int change_current_mood(const char *mood_name)
  {
@@@ -846,15 -851,18 +844,15 @@@ out
        free(aa.array);
        return ret;
  }
 -/**
 +
 +/*
   * Close and re-open the current mood.
   *
 - * This function is used if changes to the audio file table or the
 - * attribute table were made that render the current list of admissible
 - * files useless. For example, if an attribute is removed from the
 - * attribute table, this function is called.
 - *
 - * \return Positive on success, negative on errors. If no mood is currently
 - * open, the function returns success.
 + * This function is called on events which render the current list of
 + * admissible files useless, for example if an attribute is removed from the
 + * attribute table.
   *
 - * \sa mood_open(), mood_close().
 + * If no mood is currently open, the function returns success.
   */
  static int reload_current_mood(void)
  {
diff --combined server.c
index 4bc85a345b6328041059da62443a0d544371e324,af93941dd6dba2a56fc2cb63d23162f9355c46fb..2bfc1d8fc3f92ff003266de0c77e5ecf3f578a95
+++ b/server.c
  #include <arpa/inet.h>
  #include <sys/un.h>
  #include <netdb.h>
 +#include <lopsub.h>
  
 +#include "server.lsg.h"
  #include "para.h"
  #include "error.h"
  #include "crypt.h"
 -#include "server.cmdline.h"
  #include "afh.h"
  #include "string.h"
  #include "afs.h"
@@@ -63,6 -62,7 +63,6 @@@
  #include "signal.h"
  #include "user_list.h"
  #include "color.h"
 -#include "ggo.h"
  #include "version.h"
  
  /** Array of error strings. */
@@@ -80,15 -80,12 +80,15 @@@ __printf_2_3 void (*para_log)(int, cons
  struct misc_meta_data *mmd;
  
  /**
 - * The configuration of para_server
 + * The active value for all config options of para_server.
   *
 - * It also contains the options for the audio file selector, audio format
 - * handler and all supported senders.
 + * It is computed by merging the parse result of the command line options with
 + * the parse result of the config file.
   */
 -struct server_args_info conf;
 +struct lls_parse_result *server_lpr = NULL;
 +
 +/* Command line options (no config file options). Used in handle_sighup(). */
 +static struct lls_parse_result *cmdline_lpr;
  
  /** A random value used in child context for authentication. */
  uint32_t afs_socket_cookie;
@@@ -96,6 -93,9 +96,6 @@@
  /** The mutex protecting the shared memory area containing the mmd struct. */
  int mmd_mutex;
  
 -/** The file containing user information (public key, permissions). */
 -static char *user_list_file = NULL;
 -
  static struct sched sched;
  static struct signal_task *signal_task;
  
@@@ -162,97 -162,71 +162,97 @@@ err_out
  /**
   * (Re-)read the server configuration files.
   *
 - * \param override Passed to gengetopt to activate the override feature.
 + * \param reload Whether config file overrides command line.
   *
 - * This function also re-opens the logfile and sets the global \a
 - * user_list_file variable.
 + * This function also re-opens the logfile and the user list. On SIGHUP it is
 + * called from both server and afs context.
   */
 -void parse_config_or_die(int override)
 +void parse_config_or_die(bool reload)
  {
 -      char *home = para_homedir();
        int ret;
 -      char *cf;
 +      char *cf = NULL, *errctx = NULL, *user_list_file = NULL;
 +      void *map;
 +      size_t sz;
 +      int cf_argc;
 +      char **cf_argv;
 +      struct lls_parse_result *cf_lpr, *merged_lpr;
 +      char *home = para_homedir();
  
        daemon_close_log();
 -      if (conf.config_file_given)
 -              cf = para_strdup(conf.config_file_arg);
 +      if (OPT_GIVEN(CONFIG_FILE))
 +              cf = para_strdup(OPT_STRING_VAL(CONFIG_FILE));
        else
                cf = make_message("%s/.paraslash/server.conf", home);
 -      free(user_list_file);
 -      if (!conf.user_list_given)
 -              user_list_file = make_message("%s/.paraslash/server.users", home);
 -      else
 -              user_list_file = para_strdup(conf.user_list_arg);
 -      ret = file_exists(cf);
 -      if (conf.config_file_given && !ret)  {
 -              ret = -1;
 -              PARA_EMERG_LOG("can not read config file %s\n", cf);
 -              goto out;
 +      if (!mmd || getpid() != mmd->afs_pid) {
 +              if (OPT_GIVEN(USER_LIST))
 +                      user_list_file = para_strdup(OPT_STRING_VAL(USER_LIST));
 +              else
 +                      user_list_file = make_message("%s/.paraslash/server.users", home);
        }
 -      if (ret) {
 -              int tmp = conf.daemon_given;
 -              struct server_cmdline_parser_params params = {
 -                      .override = override,
 -                      .initialize = 0,
 -                      .check_required = 1,
 -                      .check_ambiguity = 0,
 -                      .print_errors = !conf.daemon_given
 -              };
 -              server_cmdline_parser_config_file(cf, &conf, &params);
 -              daemon_set_loglevel(conf.loglevel_arg);
 -              conf.daemon_given = tmp;
 +      free(home);
 +      ret = mmap_full_file(cf, O_RDONLY, &map, &sz, NULL);
 +      if (ret < 0) {
 +              if (ret != -E_EMPTY && ret != -ERRNO_TO_PARA_ERROR(ENOENT))
 +                      goto free_cf;
 +              if (ret == -ERRNO_TO_PARA_ERROR(ENOENT) && OPT_GIVEN(CONFIG_FILE))
 +                      goto free_cf;
 +              ret = 0;
 +              server_lpr = cmdline_lpr;
 +              goto success;
        }
 -      if (conf.logfile_given) {
 -              daemon_set_logfile(conf.logfile_arg);
 +      ret = lls(lls_convert_config(map, sz, NULL, &cf_argv, &errctx));
 +      para_munmap(map, sz);
 +      if (ret < 0)
 +              goto free_cf;
 +      cf_argc = ret;
 +      ret = lls(lls_parse(cf_argc, cf_argv, CMD_PTR, &cf_lpr, &errctx));
 +      lls_free_argv(cf_argv);
 +      if (ret < 0)
 +              goto free_cf;
 +      if (reload) /* config file overrides command line */
 +              ret = lls(lls_merge(cf_lpr, cmdline_lpr, CMD_PTR, &merged_lpr,
 +                      &errctx));
 +      else /* command line options overrride config file options */
 +              ret = lls(lls_merge(cmdline_lpr, cf_lpr, CMD_PTR, &merged_lpr,
 +                      &errctx));
 +      lls_free_parse_result(cf_lpr, CMD_PTR);
 +      if (ret < 0)
 +              goto free_cf;
 +      if (server_lpr != cmdline_lpr)
 +              lls_free_parse_result(server_lpr, CMD_PTR);
 +      server_lpr = merged_lpr;
 +success:
 +      daemon_set_loglevel(ENUM_STRING_VAL(LOGLEVEL));
 +      if (OPT_GIVEN(LOGFILE)) {
 +              daemon_set_logfile(OPT_STRING_VAL(LOGFILE));
                daemon_open_log_or_die();
        }
 -
 -      if (daemon_init_colors_or_die(conf.color_arg, color_arg_auto, color_arg_no,
 -                      conf.logfile_given)) {
 +      if (daemon_init_colors_or_die(OPT_UINT32_VAL(COLOR), COLOR_AUTO,
 +                      COLOR_NO, OPT_GIVEN(LOGFILE))) {
                int i;
 -              for (i = 0; i < conf.log_color_given; i++)
 -                      daemon_set_log_color_or_die(conf.log_color_arg[i]);
 +              for (i = 0; i < OPT_GIVEN(LOG_COLOR); i++)
 +                      daemon_set_log_color_or_die(lls_string_val(i,
 +                              OPT_RESULT(LOG_COLOR)));
        }
        daemon_set_flag(DF_LOG_PID);
        daemon_set_flag(DF_LOG_LL);
        daemon_set_flag(DF_LOG_TIME);
 -      if (conf.log_timing_given)
 +      if (OPT_GIVEN(LOG_TIMING))
                daemon_set_flag(DF_LOG_TIMING);
 +      daemon_set_priority(OPT_UINT32_VAL(PRIORITY));
 +      if (user_list_file)
 +              init_user_list(user_list_file);
        ret = 1;
 -out:
 +free_cf:
        free(cf);
 -      free(home);
 -      if (ret > 0)
 -              return;
        free(user_list_file);
 -      user_list_file = NULL;
 -      exit(EXIT_FAILURE);
 +      if (ret < 0) {
 +              if (errctx)
 +                      PARA_ERROR_LOG("%s\n", errctx);
 +              free(errctx);
 +              PARA_EMERG_LOG("%s\n", para_strerror(-ret));
 +              exit(EXIT_FAILURE);
 +      }
  }
  
  /*
   */
  static void handle_sighup(void)
  {
 +
        PARA_NOTICE_LOG("SIGHUP\n");
 -      parse_config_or_die(1); /* reopens log */
 -      init_user_list(user_list_file); /* reload user list */
 +      parse_config_or_die(true);
        if (mmd->afs_pid)
                kill(mmd->afs_pid, SIGHUP);
  }
@@@ -357,8 -331,6 +357,6 @@@ static int command_post_select(struct s
        ret = para_accept(sct->listen_fd, &s->rfds, NULL, 0, &new_fd);
        if (ret <= 0)
                goto out;
-       peer_name = remote_name(new_fd);
-       PARA_INFO_LOG("got connection from %s, forking\n", peer_name);
        mmd->num_connects++;
        mmd->active_connections++;
        /*
                /* parent keeps accepting connections */
                return 0;
        }
+       peer_name = remote_name(new_fd);
+       PARA_INFO_LOG("accepted connection from %s\n", peer_name);
        /* mmd might already have changed at this point */
        free(chunk_table);
        alarm(ALARM_TIMEOUT);
         */
        for (i = sct->argc - 1; i >= 0; i--)
                memset(sct->argv[i], 0, strlen(sct->argv[i]));
 -      sprintf(sct->argv[0], "para_server (serving %s)", peer_name);
 +      i = sct->argc - 1 - lls_num_inputs(cmdline_lpr);
 +      sprintf(sct->argv[i], "para_server (serving %s)", peer_name);
        handle_connect(new_fd, peer_name);
        /* never reached*/
  out:
@@@ -414,7 -387,7 +414,7 @@@ static void init_server_command_task(in
        PARA_NOTICE_LOG("initializing tcp command socket\n");
        sct->argc = argc;
        sct->argv = argv;
 -      ret = para_listen_simple(IPPROTO_TCP, conf.port_arg);
 +      ret = para_listen_simple(IPPROTO_TCP, OPT_UINT32_VAL(PORT));
        if (ret < 0)
                goto err;
        sct->listen_fd = ret;
@@@ -453,8 -426,7 +453,8 @@@ static int init_afs(int argc, char **ar
  
                for (i = argc - 1; i >= 0; i--)
                        memset(argv[i], 0, strlen(argv[i]));
 -              sprintf(argv[0], "para_server (afs)");
 +              i = argc - lls_num_inputs(cmdline_lpr) - 1;
 +              sprintf(argv[i], "para_server (afs)");
                close(afs_server_socket[0]);
                afs_init(afs_socket_cookie, afs_server_socket[1]);
        }
        return afs_server_socket[0];
  }
  
 -__noreturn static void print_help_and_die(void)
 +static void handle_help_flags(void)
  {
 -      struct ggo_help h = DEFINE_GGO_HELP(server);
 -      bool d = conf.detailed_help_given;
 +      char *help;
 +      bool d = OPT_GIVEN(DETAILED_HELP);
  
 -      ggo_print_help(&h, d? GPH_STANDARD_FLAGS_DETAILED : GPH_STANDARD_FLAGS);
 -      exit(0);
 +      if (d)
 +              help = lls_long_help(CMD_PTR);
 +      else if (OPT_GIVEN(HELP))
 +              help = lls_short_help(CMD_PTR);
 +      else
 +              return;
 +      printf("%s\n", help);
 +      free(help);
 +      exit(EXIT_SUCCESS);
  }
  
  static void server_init(int argc, char **argv)
  {
 -      struct server_cmdline_parser_params params = {
 -              .override = 0,
 -              .initialize = 1,
 -              .check_required = 0,
 -              .check_ambiguity = 0,
 -              .print_errors = 1
 -      };
 -      int afs_socket, daemon_pipe = -1;
 +      int ret, afs_socket, daemon_pipe = -1;
 +      char *errctx;
  
        valid_fd_012();
 -      init_random_seed_or_die();
        /* parse command line options */
 -      server_cmdline_parser_ext(argc, argv, &conf, &params);
 -      daemon_set_loglevel(conf.loglevel_arg);
 -      version_handle_flag("server", conf.version_given);
 -      if (conf.help_given || conf.detailed_help_given)
 -              print_help_and_die();
 -      daemon_set_priority(conf.priority_arg);
 -      daemon_drop_privileges_or_die(conf.user_arg, conf.group_arg);
 -      /* parse config file, open log and set defaults */
 -      parse_config_or_die(0);
 +      ret = lls(lls_parse(argc, argv, CMD_PTR, &cmdline_lpr, &errctx));
 +      if (ret < 0)
 +              goto fail;
 +      server_lpr = cmdline_lpr;
 +      daemon_set_loglevel(ENUM_STRING_VAL(LOGLEVEL));
 +      daemon_drop_privileges_or_die(OPT_STRING_VAL(USER),
 +              OPT_STRING_VAL(GROUP));
 +      version_handle_flag("server", OPT_GIVEN(VERSION));
 +      handle_help_flags();
 +      parse_config_or_die(false);
 +      /* become daemon */
 +      if (OPT_GIVEN(DAEMON))
 +              daemon_pipe = daemonize(true /* parent waits for SIGTERM */);
 +      init_random_seed_or_die();
        daemon_log_welcome("server");
        init_ipc_or_die(); /* init mmd struct and mmd->lock */
        daemon_set_start_time();
 -      init_user_list(user_list_file);
 -      /* become daemon */
 -      if (conf.daemon_given)
 -              daemon_pipe = daemonize(true /* parent waits for us */);
        PARA_NOTICE_LOG("initializing audio format handlers\n");
        afh_init();
  
         * Although afs uses its own signal handling we must ignore SIGUSR1
         * _before_ the afs child process gets born by init_afs() below.  It's
         * racy to do this in the child because the parent might send SIGUSR1
 -       * before the child gets a chance to ignore this signal -- only the
 -       * good die young.
 -       */
 -      para_sigaction(SIGUSR1, SIG_IGN);
 -      /*
 -       * We have to block SIGCHLD before the afs process is being forked off.
 -       * Otherwise, para_server does not notice if afs dies before the
 +       * before the child gets a chance to ignore this signal.
 +       *
 +       * We also have to block SIGCHLD before the afs process is created
 +       * because otherwise para_server does not notice if afs dies before the
         * SIGCHLD handler has been installed for the parent process by
         * init_signal_task() below.
         */
 +      para_sigaction(SIGUSR1, SIG_IGN);
        para_block_signal(SIGCHLD);
        PARA_NOTICE_LOG("initializing the audio file selector\n");
        afs_socket = init_afs(argc, argv);
        init_signal_task();
        para_unblock_signal(SIGCHLD);
        PARA_NOTICE_LOG("initializing virtual streaming system\n");
 -      init_vss_task(afs_socket, &sched);
 +      vss_init(afs_socket, &sched);
        init_server_command_task(argc, argv);
        if (daemon_pipe >= 0) {
                if (write(daemon_pipe, "\0", 1) < 0) {
                close(daemon_pipe);
        }
        PARA_NOTICE_LOG("server init complete\n");
 +      return;
 +fail:
 +      assert(ret < 0);
 +      if (errctx)
 +              PARA_ERROR_LOG("%s\n", errctx);
 +      PARA_EMERG_LOG("%s\n", para_strerror(-ret));
 +      exit(EXIT_FAILURE);
  }
  
  static void status_refresh(void)
@@@ -606,10 -572,9 +606,10 @@@ int main(int argc, char *argv[]
        mutex_lock(mmd_mutex);
        ret = schedule(&sched);
        sched_shutdown(&sched);
 -      if (ret < 0) {
 +      lls_free_parse_result(server_lpr, CMD_PTR);
 +      if (server_lpr != cmdline_lpr)
 +              lls_free_parse_result(cmdline_lpr, CMD_PTR);
 +      if (ret < 0)
                PARA_EMERG_LOG("%s\n", para_strerror(-ret));
 -              exit(EXIT_FAILURE);
 -      }
 -      exit(EXIT_SUCCESS);
 +      exit(ret < 0? EXIT_FAILURE : EXIT_SUCCESS);
  }