X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=afs.c;h=0a3d1038560f8591fddc8072d59dd3ef3df7fd78;hp=71a9f1ce6fc2d2d1b481b688e1b060a430158c94;hb=02691a995a6ee0fe4d9078f1d82465edd4814f74;hpb=c252837b853b35f06fffe637b2a6bf16419da954 diff --git a/afs.c b/afs.c index 71a9f1ce..0a3d1038 100644 --- a/afs.c +++ b/afs.c @@ -4,7 +4,7 @@ #include /* readdir() */ #include #include - +//#include #include "net.h" #include "afs.h" @@ -17,8 +17,6 @@ /** \file afs.c Paraslash's audio file selector. */ -static uint32_t socket_cookie; - /** * Compare two osl objects of string type. * @@ -71,6 +69,18 @@ enum afs_table_num { static struct table_info afs_tables[NUM_AFS_TABLES]; +struct command_task { + /** The file descriptor for the local socket. */ + int fd; + /** + * Value sent by the command handlers to identify themselves as + * children of the running para_server. + */ + uint32_t cookie; + /** The associated task structure. */ + struct task task; +}; + /** * A wrapper for strtol(3). @@ -134,6 +144,18 @@ struct callback_data { int sma_ret; }; +struct callback_query { + /** The function to be called. */ + callback_function *handler; + /** The number of bytes of the query */ + size_t query_size; +}; + +struct callback_result { + /** The number of bytes of the result. */ + size_t result_size; +}; + static struct callback_data *shm_callback_data; static int callback_mutex; static int child_mutex; @@ -463,9 +485,7 @@ static enum play_mode init_admissible_files(void) return PLAY_MODE_MOOD; } -int command_socket; - -static void setup_command_socket(void) +static int setup_command_socket_or_die(void) { int ret; char *socket_name = "/tmp/afs_command_socket"; @@ -476,13 +496,13 @@ static void setup_command_socket(void) S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IWOTH); if (ret < 0) exit(EXIT_FAILURE); - command_socket = ret; - if (listen(command_socket , 5) < 0) { + if (listen(ret , 5) < 0) { PARA_EMERG_LOG("%s", "can not listen on socket\n"); exit(EXIT_FAILURE); } PARA_INFO_LOG("listening on command socket %s (fd %d)\n", socket_name, - command_socket); + ret); + return ret; } static int server_socket; @@ -546,9 +566,142 @@ static void register_signal_task(void) register_task(&st->task); } -void register_tasks(void) +static void command_pre_select(struct sched *s, struct task *t) +{ + struct command_task *ct = t->private_data; + t->ret = 1; + para_fd_set(ct->fd, &s->rfds, &s->max_fileno); +} + +/* + * On errors, negative value is written to fd. + * On success: If query produced a result, the result_shmid is written to fd. + * Otherwise, zero is written. + */ +static int call_callback(int fd, int query_shmid) +{ + void *query_shm, *result_shm; + struct callback_query *cq; + struct callback_result *cr; + struct osl_object query, result = {.data = NULL}; + int result_shmid = -1, ret, ret2; + + ret = shm_attach(query_shmid, ATTACH_RO, &query_shm); + if (ret < 0) + goto out; + cq = query_shm; + query.data = (char *)query_shm + sizeof(*cq); + query.size = cq->query_size; + ret = cq->handler(&query, &result); + ret2 = shm_detach(query_shm); + if (ret2 < 0 && ret >= 0) + ret = ret2; + if (ret < 0) + goto out; + ret = 0; + if (!result.data || !result.size) + goto out; + ret = shm_new(result.size + sizeof(struct callback_result)); + if (ret < 0) + goto out; + result_shmid = ret; + ret = shm_attach(result_shmid, ATTACH_RW, &result_shm); + if (ret < 0) + goto out; + cr = result_shm; + cr->result_size = result.size; + memcpy(result_shm + sizeof(*cr), result.data, result.size); + ret = shm_detach(result_shm); + if (ret < 0) + goto out; + ret = result_shmid; +out: + free(result.data); + ret2 = send_bin_buffer(fd, (char *)ret, sizeof(int)); + if (ret < 0 || ret2 < 0) { + if (result_shmid >= 0) + if (shm_destroy(result_shmid) < 0) + PARA_ERROR_LOG("destroy result failed\n"); + if (ret >= 0) + ret = ret2; + } + return ret; +} + +static void command_post_select(struct sched *s, struct task *t) +{ + struct command_task *ct = t->private_data; + struct sockaddr_un unix_addr; + char buf[sizeof(uint32_t) + sizeof(int)]; + uint32_t cookie; + int query_shmid, fd; + + t->ret = 1; + if (!FD_ISSET(ct->fd, &s->rfds)) + return; + t->ret = para_accept(ct->fd, &unix_addr, sizeof(unix_addr)); + if (t->ret < 0) + return; + /* + * The following errors may be caused by a malicious local user. So do + * not return an error in this case as this would terminate para_afs + * and para_server. + */ + fd = t->ret; + t->ret = recv_bin_buffer(ct->fd, buf, sizeof(buf)); + if (t->ret < 0) { + PARA_NOTICE_LOG("%s\n", PARA_STRERROR(-t->ret)); + t->ret = 1; + goto out; + } + if (t->ret != sizeof(buf)) { + PARA_NOTICE_LOG("short read (%d bytes, expected %d)\n", + t->ret, sizeof(buf)); + t->ret = 1; + goto out; + } + cookie = *(uint32_t *)buf; + if (cookie != ct->cookie) { + PARA_NOTICE_LOG("received invalid cookie(got %u, expected %u)\n", + (unsigned)cookie, (unsigned)ct->cookie); + t->ret = 1; + goto out; + } + query_shmid = *(int *)(buf + sizeof(cookie)); + if (query_shmid < 0) { + PARA_WARNING_LOG("received invalid query shmid %d)\n", + query_shmid); + t->ret = 1; + goto out; + } + t->ret = call_callback(fd, query_shmid); + if (t->ret < 0) { + PARA_NOTICE_LOG("%s\n", PARA_STRERROR(-t->ret)); + t->ret = 1; + goto out; + } +out: + close(fd); +} + +static void register_command_task(uint32_t cookie) +{ + static struct command_task command_task_struct; + struct command_task *ct = &command_task_struct; + ct->fd = setup_command_socket_or_die(); + ct->cookie = cookie; + + ct->task.pre_select = command_pre_select; + ct->task.post_select = command_post_select; + ct->task.private_data = ct; + sprintf(ct->task.status, "command task"); + register_task(&ct->task); +} + +void register_tasks(uint32_t cookie) { register_signal_task(); + register_command_task(cookie); } __noreturn int afs_init(uint32_t cookie, int socket_fd) @@ -559,10 +712,8 @@ __noreturn int afs_init(uint32_t cookie, int socket_fd) struct sched s; server_socket = socket_fd; - socket_cookie = cookie; PARA_INFO_LOG("server_socket: %d, afs_socket_cookie: %u\n", server_socket, (unsigned) cookie); - setup_command_socket(); ret = attribute_init(&afs_tables[TBLNUM_ATTRIBUTES]); if (ret < 0) @@ -587,7 +738,7 @@ __noreturn int afs_init(uint32_t cookie, int socket_fd) goto aft_init_error; current_play_mode = init_admissible_files(); - register_tasks(); + register_tasks(cookie); s.default_timeout.tv_sec = 0; s.default_timeout.tv_usec = 99 * 1000; sched(&s); @@ -648,7 +799,7 @@ static int create_all_tables(void) } /* TODO load tables after init */ -static int com_init(__a_unused int fd, int argc, const char **argv) +int com_init(__a_unused int fd, int argc, const char **argv) { int i, j, ret; if (argc == 1) @@ -672,6 +823,8 @@ static int com_init(__a_unused int fd, int argc, const char **argv) } return 1; } + +#if 0 /** Describes a command of para_server. */ struct command { /** The name of the command. */ @@ -680,7 +833,7 @@ struct command { int (*handler)(int fd, int argc, const char **argv); }; -static struct command cmd[] = { +static struct command afs_cmds[] = { { .name = "add", .handler = com_add, @@ -854,7 +1007,6 @@ out: mutex_unlock(result_mutex); /* wake up child */ } -#if 0 static int got_sigchld; static void server_loop(int child_pid) {