X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=afs.c;h=710670255b2ec1cf67b9ab4e74823bfe19dd3a02;hp=04eed5503d18cb6d3b6e4d0cb127f98637d36b5d;hb=329bf73b72eea2c5be1bcbd9a9602c0a8994d0be;hpb=e2e1adca824585eeecd091f54955e51212927533 diff --git a/afs.c b/afs.c index 04eed550..71067025 100644 --- 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. - * - * 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. + * Passed from command handlers to afs. * - * 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. + * 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. * - * 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 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 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. */ @@ -418,13 +417,13 @@ static int pass_afd(int fd, char *buf, size_t size) */ static int open_next_audio_file(void) { - struct audio_file_data afd; - int ret, shmid; + int ret, shmid, fd; char buf[8]; - ret = open_and_update_audio_file(&afd); + ret = open_and_update_audio_file(&fd); if (ret < 0) { - PARA_ERROR_LOG("%s\n", para_strerror(-ret)); + if (ret != -OSL_ERRNO_TO_PARA_ERROR(E_OSL_RB_KEY_NOT_FOUND)) + PARA_ERROR_LOG("%s\n", para_strerror(-ret)); goto no_admissible_files; } shmid = ret; @@ -434,8 +433,8 @@ static int open_next_audio_file(void) } *(uint32_t *)buf = NEXT_AUDIO_FILE; *(uint32_t *)(buf + 4) = (uint32_t)shmid; - ret = pass_afd(afd.fd, buf, 8); - close(afd.fd); + ret = pass_afd(fd, buf, 8); + close(fd); if (ret >= 0) return ret; destroy: @@ -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(); @@ -1043,7 +1052,8 @@ static int com_init_callback(struct afs_callback_arg *aca) } ret = open_afs_tables(); if (ret < 0) - para_printf(&aca->pbout, "cannot open afs tables\n"); + para_printf(&aca->pbout, "cannot open afs tables: %s\n", + para_strerror(-ret)); out: return ret; }