audiod: Clean up fd closing logic in command handlers.
authorAndre Noll <maan@tuebingen.mpg.de>
Tue, 13 Jan 2015 22:53:28 +0000 (23:53 +0100)
committerAndre Noll <maan@tuebingen.mpg.de>
Wed, 12 Aug 2015 21:23:47 +0000 (23:23 +0200)
audiod_command.c contains this comment:

/*
 * command handlers don't close their fd on errors (ret < 0) so that
 * its caller can send an error message. Otherwise (ret >= 0) it's up
 * to each individual command to close the fd if necessary.
 */

This is a somewhat weird rule and this commit gets rid of it. Instead,
from now on the command handlers must not close their file descriptor
and handle_connect() closes it unconditionally.

The grab and stat commands need special treatment, which was the reason
for imposing the above rule. They need to keep the file descriptor open
to send the status items or the grabbed stream to the client. This
patch makes these two handlers create a copy of the descriptor with
dup(2). The new approach is simpler and less error-prone.

audiod_command.c
grab_client.c

index 0fe2e5f..2b18837 100644 (file)
@@ -110,15 +110,19 @@ static void dump_stat_client_list(void)
 static int stat_client_add(int fd, uint64_t mask, int parser_friendly)
 {
        struct stat_client *new_client;
+       int ret;
 
        if (num_clients >= MAX_STAT_CLIENTS) {
                PARA_ERROR_LOG("maximal number of stat clients (%d) exceeded\n",
                        MAX_STAT_CLIENTS);
                return -E_TOO_MANY_CLIENTS;
        }
-       PARA_INFO_LOG("adding client on fd %d\n", fd);
-       new_client = para_calloc(sizeof(struct stat_client));
-       new_client->fd = fd;
+       ret = dup(fd);
+       if (ret < 0)
+               return -ERRNO_TO_PARA_ERROR(errno);
+       new_client = para_calloc(sizeof(*new_client));
+       new_client->fd = ret;
+       PARA_INFO_LOG("adding client on fd %d\n", new_client->fd);
        new_client->item_mask = mask;
        if (parser_friendly)
                new_client->flags = SCF_PARSER_FRIENDLY;
@@ -245,22 +249,14 @@ static int dump_commands(int fd)
        return ret;
 }
 
-/*
- * command handlers don't close their fd on errors (ret < 0) so that
- * its caller can send an error message. Otherwise (ret >= 0) it's up
- * to each individual command to close the fd if necessary.
- */
-
 static int com_help(int fd, int argc, char **argv)
 {
        int i, ret;
        char *buf;
        const char *dflt = "No such command. Available commands:\n";
 
-       if (argc < 2) {
-               ret = dump_commands(fd);
-               goto out;
-       }
+       if (argc < 2)
+               return dump_commands(fd);
        FOR_EACH_COMMAND(i) {
                if (strcmp(audiod_cmds[i].name, argv[1]))
                        continue;
@@ -275,14 +271,11 @@ static int com_help(int fd, int argc, char **argv)
                );
                ret = client_write(fd, buf);
                free(buf);
-               goto out;
+               return ret;
        }
        ret = client_write(fd, dflt);
        if (ret > 0)
                ret = dump_commands(fd);
-out:
-       if (ret >= 0)
-               close(fd);
        return ret;
 }
 
@@ -294,8 +287,6 @@ static int com_tasks(int fd, __a_unused int argc, __a_unused char **argv)
        if (tl)
                ret = client_write(fd, tl);
        free(tl);
-       if (ret > 0)
-               close(fd);
        return ret;
 }
 
@@ -349,34 +340,30 @@ static int com_grab(int fd, int argc, char **argv)
        return grab_client_new(fd, argc, argv, &sched);
 }
 
-static int com_term(int fd, __a_unused int argc, __a_unused char **argv)
+static int com_term(__a_unused int fd, __a_unused int argc, __a_unused char **argv)
 {
-       close(fd);
        return -E_AUDIOD_TERM;
 }
 
-static int com_on(int fd, __a_unused int argc, __a_unused char **argv)
+static int com_on(__a_unused int fd, __a_unused int argc, __a_unused char **argv)
 {
        audiod_status = AUDIOD_ON;
-       close(fd);
        return 1;
 }
 
-static int com_off(int fd, __a_unused int argc, __a_unused char **argv)
+static int com_off(__a_unused int fd, __a_unused int argc, __a_unused char **argv)
 {
        audiod_status = AUDIOD_OFF;
-       close(fd);
        return 1;
 }
 
-static int com_sb(int fd, __a_unused int argc, __a_unused char **argv)
+static int com_sb(__a_unused int fd, __a_unused int argc, __a_unused char **argv)
 {
        audiod_status = AUDIOD_STANDBY;
-       close(fd);
        return 1;
 }
 
-static int com_cycle(int fd, int argc, char **argv)
+static int com_cycle(__a_unused int fd, int argc, char **argv)
 {
        switch (audiod_status) {
                case  AUDIOD_ON:
@@ -389,7 +376,6 @@ static int com_cycle(int fd, int argc, char **argv)
                        return com_off(fd, argc, argv);
                        break;
        }
-       close(fd);
        return 1;
 }
 
@@ -404,8 +390,6 @@ static int com_version(int fd, int argc, char **argv)
                msg = make_message("%s\n", version_single_line("audiod"));
        ret = client_write(fd, msg);
        free(msg);
-       if (ret >= 0)
-               close(fd);
        return ret;
 }
 
@@ -471,12 +455,12 @@ int handle_connect(int accept_fd, fd_set *rfds, uid_t *uid_whitelist)
        ret = -E_INVALID_AUDIOD_CMD;
 out:
        free_argv(argv);
-       if (clifd > 0 && ret < 0 && ret != -E_CLIENT_WRITE) {
+       if (ret < 0 && ret != -E_CLIENT_WRITE) {
                char *tmp = make_message("%s\n", para_strerror(-ret));
                client_write(clifd, tmp);
                free(tmp);
-               close(clifd);
        }
+       close(clifd);
        return ret;
 }
 
index 1a52917..0ef1c15 100644 (file)
@@ -284,7 +284,12 @@ int grab_client_new(int fd, int argc, char **argv, struct sched *s)
        ret = gc_check_args(argc, argv, gc);
        if (ret < 0)
                goto err_out;
-       gc->fd = fd;
+       ret = dup(fd);
+       if (ret < 0) {
+               ret = -ERRNO_TO_PARA_ERROR(errno);
+               goto err_out;
+       }
+       gc->fd = ret;
        para_list_add(&gc->node, &inactive_grab_client_list);
        gc_activate(gc, s);
        return 1;