]> git.tuebingen.mpg.de Git - paraslash.git/blobdiff - afs.c
audiod: Demote severity level of command errors.
[paraslash.git] / afs.c
diff --git a/afs.c b/afs.c
index b6cce36f42e30cd5672d7e5cc9934cc2d659ca8f..710670255b2ec1cf67b9ab4e74823bfe19dd3a02 100644 (file)
--- a/afs.c
+++ b/afs.c
@@ -39,11 +39,10 @@ enum afs_table_num {
        TBLNUM_AUDIO_FILES,
        /** The table for the paraslash attributes. See \ref attribute.c. */
        TBLNUM_ATTRIBUTES,
-       /**
-        * Paraslash's scoring system is based on Gaussian normal
-        * distributions, and the relevant data is stored in the rbtrees of an
-        * osl table containing only volatile columns. See \ref score.c for
-        * details.
+       /*
+        * Moods and playlists organize the current set of admissible files in
+        * an osl table which contains only volatile columns. Each row consists
+        * of a pointer to an audio file and the score value of this file.
         */
        TBLNUM_SCORES,
        /**
@@ -91,26 +90,26 @@ static char *current_mop; /* mode or playlist specifier. NULL means dummy mood *
 extern uint32_t afs_socket_cookie;
 
 /**
- * Struct to let command handlers execute a callback in afs context.
+ * Passed from command handlers to afs.
  *
- * Commands that need to change the state of afs can't change the relevant data
- * structures directly because commands are executed in a child process, i.e.
- * they get their own virtual address space.
+ * Command handlers cannot change the afs database directly because they run in
+ * a separate process. The callback query structure circumvents this
+ * restriction as follows. To instruct the afs process to execute a particular
+ * function, the command hander writes an instance of this structure to a
+ * shared memory area, along with the arguments to the callback function. The
+ * identifier of the shared memory area is transferred to the afs process via
+ * the command socket.
  *
- * This structure is used by \p send_callback_request() (executed from handler
- * context) in order to let the afs process call the specified function. An
- * instance of that structure is written to a shared memory area together with
- * the arguments to the callback function. The identifier of the shared memory
- * area is written to the command socket.
+ * The afs process reads the shared memory id from the command socket, attaches
+ * the corresponding area, and calls the callback function whose address is
+ * stored in the area.
  *
- * The afs process accepts connections on the command socket and reads the
- * shared memory id, attaches the corresponding area, calls the given handler to
- * perform the desired action and to optionally compute a result.
- *
- * The result and a \p callback_result structure is then written to another
- * shared memory area. The identifier for that area is written to the handler's
- * command socket, so that the handler process can read the id, attach the
- * shared memory area and use the result.
+ * The command output, if any, is transferred back to the command handler in
+ * the same way: The afs process writes the output to a second shared memory
+ * area together with a fixed size metadata header whose format corresponds to
+ * the \ref callback_result structure. The identifier of this area is sent back
+ * to the command handler which attaches the area and forwards the output to
+ * the remote client.
  *
  * \sa \ref struct callback_result.
  */
@@ -447,7 +446,6 @@ no_admissible_files:
        return write_all(server_socket, buf, 8);
 }
 
-/* Never fails if arg == NULL */
 static int activate_mood_or_playlist(const char *arg, int *num_admissible,
                char **errmsg)
 {
@@ -455,8 +453,13 @@ static int activate_mood_or_playlist(const char *arg, int *num_admissible,
        int ret;
 
        if (!arg) {
-               ret = change_current_mood(NULL, NULL); /* always successful */
                mode = PLAY_MODE_MOOD;
+               ret = change_current_mood(NULL, errmsg);
+               if (ret < 0) {
+                       if (num_admissible)
+                               *num_admissible = 0;
+                       return ret;
+               }
        } else {
                if (!strncmp(arg, "p/", 2)) {
                        ret = playlist_open(arg + 2);
@@ -478,6 +481,12 @@ static int activate_mood_or_playlist(const char *arg, int *num_admissible,
        if (num_admissible)
                *num_admissible = ret;
        current_play_mode = mode;
+       /*
+        * We get called with arg == current_mop from the signal dispatcher
+        * after SIGHUP and from the error path of the select command to
+        * re-select the current mood or playlist. In this case the assignment
+        * to current_mop below would result in a use-after-free condition.
+        */
        if (arg != current_mop) {
                free(current_mop);
                if (arg) {
@@ -615,10 +624,10 @@ static void init_admissible_files(const char *arg)
 {
        int ret = activate_mood_or_playlist(arg, NULL, NULL);
        if (ret < 0) {
-               assert(arg);
                PARA_WARNING_LOG("could not activate %s: %s\n", arg,
                        para_strerror(-ret));
-               activate_mood_or_playlist(NULL, NULL, NULL);
+               if (arg)
+                       activate_mood_or_playlist(NULL, NULL, NULL);
        }
 }
 
@@ -644,7 +653,7 @@ static char *database_dir;
 static void close_afs_tables(void)
 {
        int i;
-       PARA_NOTICE_LOG("closing afs_tables\n");
+       PARA_NOTICE_LOG("closing afs tables\n");
        for (i = 0; i < NUM_AFS_TABLES; i++)
                afs_tables[i].close();
        free(database_dir);
@@ -659,7 +668,7 @@ static void get_database_dir(void)
                else {
                        char *home = para_homedir();
                        database_dir = make_message(
-                               "%s/.paraslash/afs_database-0.4", home);
+                               "%s/.paraslash/afs_database-0.7", home);
                        free(home);
                }
        }
@@ -981,7 +990,7 @@ __noreturn void afs_init(int socket_fd)
        int i, ret;
 
        register_signal_task(&s);
-       INIT_LIST_HEAD(&afs_client_list);
+       init_list_head(&afs_client_list);
        for (i = 0; i < NUM_AFS_TABLES; i++)
                afs_tables[i].init(&afs_tables[i]);
        ret = open_afs_tables();