X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=afs.c;h=46ed6913626482c07eae50c99b943aaa39e275db;hp=1350db3423c3a184cb645e09cae9a2ebb060358b;hb=748d1368bc96dd7e1af879df1ea41b4d52842f7e;hpb=7205bdd68b0ad3c50bbe7b5e01eb62be97aab5c8 diff --git a/afs.c b/afs.c index 1350db34..46ed6913 100644 --- a/afs.c +++ b/afs.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2009 Andre Noll + * Copyright (C) 2007-2012 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -9,7 +9,6 @@ #include #include #include -#include #include #include "server.cmdline.h" @@ -20,9 +19,6 @@ #include "afh.h" #include "afs.h" #include "server.h" -#include /* readdir() */ -#include -#include #include "net.h" #include "ipc.h" #include "list.h" @@ -196,7 +192,7 @@ static int dispatch_result(int result_shmid, callback_result_handler *handler, * shmid are passed to that function as an osl object. The private_result_data * pointer is passed as the second argument to \a result_handler. * - * \return Standard. + * \return Number of shared memory areas dispatched on success, negative on errors. * * \sa send_option_arg_callback_request(), send_standard_callback_request(). */ @@ -209,7 +205,7 @@ int send_callback_request(callback_function *f, struct osl_object *query, void *query_shm; char buf[sizeof(afs_socket_cookie) + sizeof(int)]; size_t query_shm_size = sizeof(*cq); - int dispatch_error = 0; + int dispatch_error = 0, num_dispatched = 0; if (query) query_shm_size += query->size; @@ -233,11 +229,11 @@ int send_callback_request(callback_function *f, struct osl_object *query, *(uint32_t *) buf = afs_socket_cookie; *(int *) (buf + sizeof(afs_socket_cookie)) = query_shmid; - ret = create_remote_socket(conf.afs_socket_arg); + ret = connect_local_socket(conf.afs_socket_arg); if (ret < 0) goto out; fd = ret; - ret = send_bin_buffer(fd, buf, sizeof(buf)); + ret = write_all(fd, buf, sizeof(buf)); if (ret < 0) goto out; /* @@ -265,6 +261,7 @@ int send_callback_request(callback_function *f, struct osl_object *query, if (ret < 0) PARA_CRIT_LOG("destroy result failed: %s\n", para_strerror(-ret)); + num_dispatched++; } out: if (shm_destroy(query_shmid) < 0) @@ -272,7 +269,7 @@ out: if (fd >= 0) close(fd); // PARA_DEBUG_LOG("callback_ret: %d\n", ret); - return ret; + return ret < 0? ret : num_dispatched; } /** @@ -290,6 +287,9 @@ out: * command. This function allows to pass such a structure together with a list * of further arguments (often a list of audio files) to the parent process. * + * \return The return value of the underlying call to \ref + * send_callback_request(). + * * \sa send_standard_callback_request(), send_callback_request(). */ int send_option_arg_callback_request(struct osl_object *options, @@ -364,7 +364,10 @@ static int action_if_pattern_matches(struct osl_row *row, void *data) continue; if (ret) return -E_FNMATCH; - return pmd->action(pmd->table, row, name, pmd->data); + ret = pmd->action(pmd->table, row, name, pmd->data); + if (ret >= 0) + pmd->num_matches++; + return ret; } return 1; } @@ -468,7 +471,6 @@ again: } ret = open_and_update_audio_file(aft_row, score, &afd); if (ret < 0) { - PARA_ERROR_LOG("%s\n", para_strerror(-ret)); ret = score_delete(aft_row); if (ret < 0) { PARA_ERROR_LOG("%s\n", para_strerror(-ret)); @@ -493,7 +495,7 @@ destroy: no_admissible_files: *(uint32_t *)buf = NO_ADMISSIBLE_FILES; *(uint32_t *)(buf + 4) = (uint32_t)0; - return send_bin_buffer(server_socket, buf, 8); + return write_all(server_socket, buf, 8); } /* Never fails if arg == NULL */ @@ -542,7 +544,7 @@ static int activate_mood_or_playlist(char *arg, int *num_admissible) static void com_select_callback(int fd, const struct osl_object *query) { struct para_buffer pb = { - .max_size = SHMMAX, + .max_size = shm_get_shmmax(), .private_data = &fd, .max_size_handler = pass_buffer_as_shm }; @@ -582,22 +584,22 @@ out: * Result handler for sending data to the para_client process. * * \param result The data to be sent. - * \param private Pointer to rc4 context. + * \param private Pointer to the context. * - * \return The return value of the underlying call to rc4_send_bin_buffer(). + * \return The return value of the underlying call to sc_send_bin_buffer(). * - * \sa \ref callback_result_handler, \ref rc4_send_bin_buffer(). + * \sa \ref callback_result_handler, \ref sc_send_bin_buffer(). */ -int rc4_send_result(struct osl_object *result, void *private) +int sc_send_result(struct osl_object *result, void *private) { - struct rc4_context *rc4c = private; + struct stream_cipher_context *scc = private; if (!result->size) return 1; - return rc4_send_bin_buffer(rc4c, result->data, result->size); + return sc_send_bin_buffer(scc, result->data, result->size); } -int com_select(struct rc4_context *rc4c, int argc, char * const * const argv) +int com_select(struct stream_cipher_context *scc, int argc, char * const * const argv) { struct osl_object query; @@ -606,7 +608,7 @@ int com_select(struct rc4_context *rc4c, int argc, char * const * const argv) query.data = argv[1]; query.size = strlen(argv[1]) + 1; return send_callback_request(com_select_callback, &query, - &rc4_send_result, rc4c); + &sc_send_result, scc); } static void init_admissible_files(char *arg) @@ -709,15 +711,16 @@ static void signal_pre_select(struct sched *s, struct task *t) static void afs_signal_post_select(struct sched *s, struct task *t) { - struct signal_task *st = container_of(t, struct signal_task, task); + int signum; + if (getppid() == 1) { PARA_EMERG_LOG("para_server died\n"); goto shutdown; } - if (!FD_ISSET(st->fd, &s->rfds)) + signum = para_next_signal(&s->rfds); + if (signum == 0) return; - st->signum = para_next_signal(); - if (st->signum == SIGHUP) { + if (signum == SIGHUP) { close_afs_tables(); parse_config_or_die(1); t->error = open_afs_tables(); @@ -726,13 +729,13 @@ static void afs_signal_post_select(struct sched *s, struct task *t) init_admissible_files(current_mop); return; } - PARA_EMERG_LOG("terminating on signal %d\n", st->signum); + PARA_EMERG_LOG("terminating on signal %d\n", signum); shutdown: - sched_shutdown(); + sched_shutdown(s); t->error = -E_AFS_SIGNAL; } -static void register_signal_task(void) +static void register_signal_task(struct sched *s) { struct signal_task *st = &signal_task_struct; @@ -746,7 +749,7 @@ static void register_signal_task(void) st->task.pre_select = signal_pre_select; st->task.post_select = afs_signal_post_select; sprintf(st->task.status, "signal task"); - register_task(&st->task); + register_task(s, &st->task); } static struct list_head afs_client_list; @@ -811,7 +814,7 @@ int pass_buffer_as_shm(char *buf, size_t size, void *fd_ptr) ret = shm_detach(shm); if (ret < 0) goto err; - ret = send_bin_buffer(fd, (char *)&shmid, sizeof(int)); + ret = write_all(fd, (char *)&shmid, sizeof(int)); if (ret >= 0) return ret; err: @@ -842,57 +845,56 @@ static int call_callback(int fd, int query_shmid) return shm_detach(query_shm); } -static int execute_server_command(void) +static int execute_server_command(fd_set *rfds) { char buf[8]; - int ret = recv_bin_buffer(server_socket, buf, sizeof(buf) - 1); + size_t n; + int ret = read_nonblock(server_socket, buf, sizeof(buf) - 1, rfds, &n); - if (ret <= 0) { - if (!ret) - ret = -ERRNO_TO_PARA_ERROR(ECONNRESET); - goto err; - } - buf[ret] = '\0'; - PARA_DEBUG_LOG("received: %s\n", buf); - ret = -E_BAD_CMD; + if (ret < 0 || n == 0) + return ret; + buf[n] = '\0'; if (strcmp(buf, "new")) - goto err; - ret = open_next_audio_file(); -err: - return ret; + return -E_BAD_CMD; + return open_next_audio_file(); } -static void execute_afs_command(int fd, uint32_t expected_cookie) +/* returns 0 if no data available, 1 else */ +static int execute_afs_command(int fd, fd_set *rfds, uint32_t expected_cookie) { uint32_t cookie; int query_shmid; char buf[sizeof(cookie) + sizeof(query_shmid)]; - int ret = recv_bin_buffer(fd, buf, sizeof(buf)); + size_t n; + int ret = read_nonblock(fd, buf, sizeof(buf), rfds, &n); if (ret < 0) goto err; - if (ret != sizeof(buf)) { + if (n == 0) + return 0; + if (n != sizeof(buf)) { PARA_NOTICE_LOG("short read (%d bytes, expected %lu)\n", ret, (long unsigned) sizeof(buf)); - return; + return 1; } cookie = *(uint32_t *)buf; if (cookie != expected_cookie) { - PARA_NOTICE_LOG("received invalid cookie(got %u, expected %u)\n", + PARA_NOTICE_LOG("received invalid cookie (got %u, expected %u)\n", (unsigned)cookie, (unsigned)expected_cookie); - return; + return 1; } query_shmid = *(int *)(buf + sizeof(cookie)); if (query_shmid < 0) { PARA_WARNING_LOG("received invalid query shmid %d)\n", query_shmid); - return; + return 1; } ret = call_callback(fd, query_shmid); if (ret >= 0) - return; + return 1; err: PARA_NOTICE_LOG("%s\n", para_strerror(-ret)); + return 1; } /** Shutdown connection if query has not arrived until this many seconds. */ @@ -905,20 +907,16 @@ static void command_post_select(struct sched *s, struct task *t) struct afs_client *client, *tmp; int fd, ret; - if (FD_ISSET(server_socket, &s->rfds)) { - ret = execute_server_command(); - if (ret < 0) { - PARA_EMERG_LOG("%s\n", para_strerror(-ret)); - sched_shutdown(); - return; - } + ret = execute_server_command(&s->rfds); + if (ret < 0) { + PARA_EMERG_LOG("%s\n", para_strerror(-ret)); + sched_shutdown(s); + return; } - /* Check the list of connected clients. */ list_for_each_entry_safe(client, tmp, &afs_client_list, node) { - if (FD_ISSET(client->fd, &s->rfds)) - execute_afs_command(client->fd, ct->cookie); - else { /* prevent bogus connection flooding */ + ret = execute_afs_command(client->fd, &s->rfds, ct->cookie); + if (ret == 0) { /* prevent bogus connection flooding */ struct timeval diff; tv_diff(now, &client->connect_time, &diff); if (diff.tv_sec < AFS_CLIENT_TIMEOUT) @@ -930,14 +928,11 @@ static void command_post_select(struct sched *s, struct task *t) free(client); } /* Accept connections on the local socket. */ - if (!FD_ISSET(ct->fd, &s->rfds)) - return; - ret = para_accept(ct->fd, &unix_addr, sizeof(unix_addr)); - if (ret < 0) { + ret = para_accept(ct->fd, &s->rfds, &unix_addr, sizeof(unix_addr), &fd); + if (ret < 0) PARA_NOTICE_LOG("%s\n", para_strerror(-ret)); + if (ret <= 0) return; - } - fd = ret; ret = mark_fd_nonblocking(fd); if (ret < 0) { PARA_NOTICE_LOG("%s\n", para_strerror(-ret)); @@ -950,7 +945,7 @@ static void command_post_select(struct sched *s, struct task *t) para_list_add(&client->node, &afs_client_list); } -static void register_command_task(uint32_t cookie) +static void register_command_task(uint32_t cookie, struct sched *s) { struct command_task *ct = &command_task_struct; ct->fd = setup_command_socket_or_die(); @@ -958,8 +953,8 @@ static void register_command_task(uint32_t cookie) ct->task.pre_select = command_pre_select; ct->task.post_select = command_post_select; - sprintf(ct->task.status, "command task"); - register_task(&ct->task); + sprintf(ct->task.status, "afs command task"); + register_task(s, &ct->task); } /** @@ -973,7 +968,7 @@ __noreturn void afs_init(uint32_t cookie, int socket_fd) static struct sched s; int i, ret; - register_signal_task(); + register_signal_task(&s); INIT_LIST_HEAD(&afs_client_list); for (i = 0; i < NUM_AFS_TABLES; i++) afs_tables[i].init(&afs_tables[i]); @@ -987,7 +982,7 @@ __noreturn void afs_init(uint32_t cookie, int socket_fd) PARA_INFO_LOG("server_socket: %d, afs_socket_cookie: %u\n", server_socket, (unsigned) cookie); init_admissible_files(conf.afs_initial_mode_arg); - register_command_task(cookie); + register_command_task(cookie, &s); s.default_timeout.tv_sec = 0; s.default_timeout.tv_usec = 999 * 1000; ret = schedule(&s); @@ -1027,7 +1022,7 @@ out: free(pb.buf); } -int com_init(struct rc4_context *rc4c, int argc, char * const * const argv) +int com_init(struct stream_cipher_context *scc, int argc, char * const * const argv) { int i, j, ret; uint32_t table_mask = (1 << (NUM_AFS_TABLES + 1)) - 1; @@ -1053,9 +1048,10 @@ int com_init(struct rc4_context *rc4c, int argc, char * const * const argv) } } ret = send_callback_request(create_tables_callback, &query, - rc4_send_result, rc4c); + sc_send_result, scc); if (ret < 0) - return rc4_send_va_buffer(rc4c, "%s\n", para_strerror(-ret)); + /* ignore return value */ + sc_send_va_buffer(scc, "%s\n", para_strerror(-ret)); return ret; } @@ -1073,7 +1069,7 @@ enum com_check_flags { CHECK_PLAYLISTS = 4 }; -int com_check(struct rc4_context *rc4c, int argc, char * const * const argv) +int com_check(struct stream_cipher_context *scc, int argc, char * const * const argv) { unsigned flags = 0; int i, ret; @@ -1106,19 +1102,19 @@ int com_check(struct rc4_context *rc4c, int argc, char * const * const argv) flags = ~0U; if (flags & CHECK_AFT) { ret = send_callback_request(aft_check_callback, NULL, - rc4_send_result, rc4c); + sc_send_result, scc); if (ret < 0) return ret; } if (flags & CHECK_PLAYLISTS) { ret = send_callback_request(playlist_check_callback, - NULL, rc4_send_result, rc4c); + NULL, sc_send_result, scc); if (ret < 0) return ret; } if (flags & CHECK_MOODS) { ret = send_callback_request(mood_check_callback, NULL, - rc4_send_result, rc4c); + sc_send_result, scc); if (ret < 0) return ret; } @@ -1151,13 +1147,33 @@ void afs_event(enum afs_events event, struct para_buffer *pb, } } -int images_event_handler(__a_unused enum afs_events event, +/** + * Dummy event handler for the images table. + * + * \param event Unused. + * \param pb Unused. + * \param data Unused. + * + * \return The images table does not honor events, so this handler always + * returns success. + */ +__a_const int images_event_handler(__a_unused enum afs_events event, __a_unused struct para_buffer *pb, __a_unused void *data) { return 1; } -int lyrics_event_handler(__a_unused enum afs_events event, +/** + * Dummy event handler for the lyrics table. + * + * \param event Unused. + * \param pb Unused. + * \param data Unused. + * + * \return The lyrics table does not honor events, so this handler always + * returns success. + */ +__a_const int lyrics_event_handler(__a_unused enum afs_events event, __a_unused struct para_buffer *pb, __a_unused void *data) { return 1;