X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=afs.c;h=b40fe8e05c943eb503b3a2344fc1287db81b3696;hp=02b6b56db561d5a7ef2f9464dc2c1f1c54f35fec;hb=672e27768e31a6eaa6854d4fc75ee6885db9abd8;hpb=6bdac07456cb5872f824028912d1049883a9c21f;ds=inline diff --git a/afs.c b/afs.c index 02b6b56d..b40fe8e0 100644 --- a/afs.c +++ b/afs.c @@ -8,9 +8,13 @@ #include #include +#include +#include + #include "server.cmdline.h" #include "para.h" #include "error.h" +#include "crypt.h" #include "string.h" #include "afh.h" #include "afs.h" @@ -85,7 +89,6 @@ static struct signal_task signal_task_struct; static enum play_mode current_play_mode; static char *current_mop; /* mode or playlist specifier. NULL means dummy mooe */ - /** * A random number used to "authenticate" the connection. * @@ -141,6 +144,36 @@ struct callback_result { size_t result_size; }; +static int dispatch_result(int result_shmid, callback_result_handler *handler, + void *private_result_data) +{ + struct osl_object result; + void *result_shm; + int ret2, ret = shm_attach(result_shmid, ATTACH_RO, &result_shm); + struct callback_result *cr = result_shm; + + if (ret < 0) { + PARA_ERROR_LOG("attach failed: %s\n", para_strerror(-ret)); + return ret; + } + result.size = cr->result_size; + result.data = result_shm + sizeof(*cr); + if (result.size) { + assert(handler); + ret = handler(&result, private_result_data); + if (ret < 0) + PARA_NOTICE_LOG("result handler error: %s\n", + para_strerror(-ret)); + } + ret2 = shm_detach(result_shm); + if (ret2 < 0) { + PARA_ERROR_LOG("detach failed: %s\n", para_strerror(-ret2)); + if (ret >= 0) + ret = ret2; + } + return ret; +} + /** * Ask the afs process to call a given function. * @@ -161,8 +194,7 @@ struct callback_result { * 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 Negative, on errors, the return value of the callback function - * otherwise. + * \return Standard. * * \sa send_option_arg_callback_request(), send_standard_callback_request(). */ @@ -171,10 +203,11 @@ int send_callback_request(callback_function *f, struct osl_object *query, void *private_result_data) { struct callback_query *cq; - int num_results = 0, ret, fd = -1, query_shmid, result_shmid; - void *query_shm, *result_shm; + int ret, fd = -1, query_shmid, result_shmid; + void *query_shm; char buf[sizeof(afs_socket_cookie) + sizeof(int)]; size_t query_shm_size = sizeof(*cq); + int dispatch_error = 0; if (query) query_shm_size += query->size; @@ -205,45 +238,37 @@ int send_callback_request(callback_function *f, struct osl_object *query, ret = send_bin_buffer(fd, buf, sizeof(buf)); if (ret < 0) goto out; + /* + * Read all shmids from afs. + * + * Even if the dispatcher returns an error we _must_ continue to read + * shmids from fd so that we can destroy all shared memory areas that + * have been created for us by the afs process. + */ for (;;) { ret = recv_bin_buffer(fd, buf, sizeof(int)); if (ret <= 0) goto out; - if (ret != sizeof(int)) { - ret = -E_AFS_SHORT_READ; - goto out; - } + assert(ret == sizeof(int)); ret = *(int *) buf; - if (ret <= 0) - goto out; + assert(ret > 0); result_shmid = ret; - ret = shm_attach(result_shmid, ATTACH_RO, &result_shm); - if (ret >= 0) { - struct callback_result *cr = result_shm; - struct osl_object result; - num_results++; - result.size = cr->result_size; - result.data = result_shm + sizeof(*cr); - if (result.size) { - assert(result_handler); - ret = result_handler(&result, private_result_data); - if (shm_detach(result_shm) < 0) - PARA_ERROR_LOG("can not detach result\n"); - } - } else - PARA_ERROR_LOG("attach result failed: %d\n", ret); - if (shm_destroy(result_shmid) < 0) - PARA_ERROR_LOG("destroy result failed\n"); + if (!dispatch_error) { + ret = dispatch_result(result_shmid, result_handler, + private_result_data); + if (ret < 0) + dispatch_error = 1; + } + ret = shm_destroy(result_shmid); if (ret < 0) - break; + PARA_CRIT_LOG("destroy result failed: %s\n", + para_strerror(-ret)); } out: if (shm_destroy(query_shmid) < 0) - PARA_ERROR_LOG("%s\n", "shm destroy error"); + PARA_CRIT_LOG("shm destroy error\n"); if (fd >= 0) close(fd); - if (ret >= 0) - ret = num_results; // PARA_DEBUG_LOG("callback_ret: %d\n", ret); return ret; } @@ -320,7 +345,7 @@ static int action_if_pattern_matches(struct osl_row *row, void *data) struct pattern_match_data *pmd = data; struct osl_object name_obj; const char *p, *name; - int ret = osl_get_object(pmd->table, row, pmd->match_col_num, &name_obj); + int ret = osl(osl_get_object(pmd->table, row, pmd->match_col_num, &name_obj)); const char *pattern_txt = (const char *)pmd->patterns.data; if (ret < 0) @@ -347,16 +372,15 @@ static int action_if_pattern_matches(struct osl_row *row, void *data) * * \param pmd Describes what to match and how. * - * \return The return value of the underlying call to osl_rbtree_loop() - * or osl_rbtree_loop_reverse(). + * \return Standard. */ int for_each_matching_row(struct pattern_match_data *pmd) { if (pmd->pm_flags & PM_REVERSE_LOOP) - return osl_rbtree_loop_reverse(pmd->table, pmd->loop_col_num, pmd, - action_if_pattern_matches); - return osl_rbtree_loop(pmd->table, pmd->loop_col_num, pmd, - action_if_pattern_matches); + return osl(osl_rbtree_loop_reverse(pmd->table, pmd->loop_col_num, pmd, + action_if_pattern_matches)); + return osl(osl_rbtree_loop(pmd->table, pmd->loop_col_num, pmd, + action_if_pattern_matches)); } /** @@ -381,80 +405,6 @@ int string_compare(const struct osl_object *obj1, const struct osl_object *obj2) return strncmp(str1, str2, PARA_MIN(obj1->size, obj2->size)); } -/* - * write input from fd to dynamically allocated buffer, - * but maximal max_size byte. - */ -static int fd2buf(int fd, unsigned max_size, struct osl_object *obj) -{ - const size_t chunk_size = 1024; - size_t size = 2048, received = 0; - int ret; - char *buf = para_malloc(size); - - for (;;) { - ret = recv_bin_buffer(fd, buf + received, chunk_size); - if (ret <= 0) - break; - received += ret; - if (received + chunk_size >= size) { - size *= 2; - ret = -E_INPUT_TOO_LARGE; - if (size > max_size) - break; - buf = para_realloc(buf, size); - } - } - obj->data = buf; - obj->size = received; - if (ret < 0) - free(buf); - return ret; -} - -/** - * Read data from a file descriptor, and send it to the afs process. - * - * \param fd File descriptor to read data from. - * \param arg_obj Pointer to the arguments to \a f. - * \param f The callback function. - * \param max_len Don't read more than that many bytes from stdin. - * \param result_handler See \ref send_callback_request. - * \param private_result_data See \ref send_callback_request. - * - * This function is used by commands that wish to let para_server store - * arbitrary data specified by the user (for instance the add_blob family of - * commands). First, at most \a max_len bytes are read from \a fd, the result - * is concatenated with the buffer given by \a arg_obj, and the combined buffer - * is made available to the afs process via the callback method. See \ref - * send_callback_request for details. - * - * \return Negative on errors, the return value of the underlying call to - * send_callback_request() otherwise. - */ -int stdin_command(int fd, struct osl_object *arg_obj, callback_function *f, - unsigned max_len, callback_result_handler *result_handler, - void *private_result_data) -{ - struct osl_object query, stdin_obj; - int ret; - - ret = send_buffer(fd, AWAITING_DATA_MSG); - if (ret < 0) - return ret; - ret = fd2buf(fd, max_len, &stdin_obj); - if (ret < 0) - return ret; - query.size = arg_obj->size + stdin_obj.size; - query.data = para_malloc(query.size); - memcpy(query.data, arg_obj->data, arg_obj->size); - memcpy((char *)query.data + arg_obj->size, stdin_obj.data, stdin_obj.size); - free(stdin_obj.data); - ret = send_callback_request(f, &query, result_handler, private_result_data); - free(query.data); - return ret; -} - static int pass_afd(int fd, char *buf, size_t size) { struct msghdr msg = {.msg_iov = NULL}; @@ -630,21 +580,22 @@ out: * Result handler for sending data to the para_client process. * * \param result The data to be sent. - * \param fd_ptr Pointer to the file descriptor. + * \param private Pointer to rc4 context. * - * \return The return value of the underlying call to send_bin_buffer(). + * \return The return value of the underlying call to rc4_send_bin_buffer(). * - * \sa \ref callback_result_handler. + * \sa \ref callback_result_handler, \ref rc4_send_bin_buffer(). */ -int send_result(struct osl_object *result, void *fd_ptr) +int rc4_send_result(struct osl_object *result, void *private) { - int fd = *(int *)fd_ptr; + struct rc4_context *rc4c = private; + if (!result->size) return 1; - return send_bin_buffer(fd, result->data, result->size); + return rc4_send_bin_buffer(rc4c, result->data, result->size); } -int com_select(int fd, int argc, char * const * const argv) +int com_select(struct rc4_context *rc4c, int argc, char * const * const argv) { struct osl_object query; @@ -653,7 +604,7 @@ int com_select(int fd, int argc, char * const * const argv) query.data = argv[1]; query.size = strlen(argv[1]) + 1; return send_callback_request(com_select_callback, &query, - &send_result, &fd); + &rc4_send_result, rc4c); } static void init_admissible_files(char *arg) @@ -708,7 +659,7 @@ static void get_database_dir(void) else { char *home = para_homedir(); database_dir = make_message( - "%s/.paraslash/afs_database", home); + "%s/.paraslash/afs_database-0.4", home); free(home); } } @@ -754,7 +705,7 @@ static void signal_pre_select(struct sched *s, struct task *t) para_fd_set(st->fd, &s->rfds, &s->max_fileno); } -static void signal_post_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); if (getppid() == 1) { @@ -766,6 +717,7 @@ static void signal_post_select(struct sched *s, struct task *t) st->signum = para_next_signal(); if (st->signum == SIGHUP) { close_afs_tables(); + parse_config_or_die(1); t->error = open_afs_tables(); if (t->error < 0) return; @@ -782,14 +734,7 @@ static void register_signal_task(void) { struct signal_task *st = &signal_task_struct; - if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) { - PARA_EMERG_LOG("failed to ignore SIGPIPE\n"); - exit(EXIT_FAILURE); - } - if (signal(SIGUSR1, SIG_IGN) == SIG_ERR) { - PARA_EMERG_LOG("failed to ignore SIGUSR1\n"); - exit(EXIT_FAILURE); - } + para_sigaction(SIGPIPE, SIG_IGN); st->fd = para_signal_init(); PARA_INFO_LOG("signal pipe: fd %d\n", st->fd); para_install_sighandler(SIGINT); @@ -797,7 +742,7 @@ static void register_signal_task(void) para_install_sighandler(SIGHUP); st->task.pre_select = signal_pre_select; - st->task.post_select = signal_post_select; + st->task.post_select = afs_signal_post_select; sprintf(st->task.status, "signal task"); register_task(&st->task); } @@ -1080,7 +1025,7 @@ out: free(buf); } -int com_init(int fd, int argc, char * const * const argv) +int com_init(struct rc4_context *rc4c, int argc, char * const * const argv) { int i, j, ret; uint32_t table_mask = (1 << (NUM_AFS_TABLES + 1)) - 1; @@ -1105,9 +1050,10 @@ int com_init(int fd, int argc, char * const * const argv) return -E_BAD_TABLE_NAME; } } - ret = send_callback_request(create_tables_callback, &query, &send_result, &fd); + ret = send_callback_request(create_tables_callback, &query, + rc4_send_result, rc4c); if (ret < 0) - return send_va_buffer(fd, "%s\n", para_strerror(-ret)); + return rc4_send_va_buffer(rc4c, "%s\n", para_strerror(-ret)); return ret; } @@ -1125,7 +1071,7 @@ enum com_check_flags { CHECK_PLAYLISTS = 4 }; -int com_check(int fd, int argc, char * const * const argv) +int com_check(struct rc4_context *rc4c, int argc, char * const * const argv) { unsigned flags = 0; int i, ret; @@ -1157,23 +1103,36 @@ int com_check(int fd, int argc, char * const * const argv) if (!flags) flags = ~0U; if (flags & CHECK_AFT) { - ret = send_callback_request(aft_check_callback, NULL, send_result, &fd); + ret = send_callback_request(aft_check_callback, NULL, + rc4_send_result, rc4c); if (ret < 0) return ret; } if (flags & CHECK_PLAYLISTS) { - ret = send_callback_request(playlist_check_callback, NULL, send_result, &fd); + ret = send_callback_request(playlist_check_callback, + NULL, rc4_send_result, rc4c); if (ret < 0) return ret; } if (flags & CHECK_MOODS) { - ret = send_callback_request(mood_check_callback, NULL, send_result, &fd); + ret = send_callback_request(mood_check_callback, NULL, + rc4_send_result, rc4c); if (ret < 0) return ret; } return 1; } +/** + * The afs event dispatcher. + * + * \param event Type of the event. + * \param pb May be \p NULL. + * \param data Type depends on \a event. + * + * This function calls the table handlers of all tables and passes \a pb and \a + * data verbatim. It's up to the handlers to interpret the \a data pointer. + */ void afs_event(enum afs_events event, struct para_buffer *pb, void *data) {