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,
/**
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.
*/
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)
{
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);
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) {
{
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);
}
}
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);
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);
}
}