Date: Thu, 4 Aug 2005 11:43:19 GMT From: soc-bushman <soc-bushman@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 81439 for review Message-ID: <200508041143.j74BhJ5K074641@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=81439 Change 81439 by soc-bushman@soc-bushman_stinger on 2005/08/04 11:42:58 cached work in progress Affected files ... .. //depot/projects/soc2005/nsswitch_cached/cached/Makefile#2 edit .. //depot/projects/soc2005/nsswitch_cached/cached/cached.c#2 edit .. //depot/projects/soc2005/nsswitch_cached/cached/config.c#2 edit .. //depot/projects/soc2005/nsswitch_cached/cached/config.h#2 edit .. //depot/projects/soc2005/nsswitch_cached/cached/debug.c#2 edit .. //depot/projects/soc2005/nsswitch_cached/cached/debug.h#2 edit .. //depot/projects/soc2005/nsswitch_cached/cached/log.c#2 edit .. //depot/projects/soc2005/nsswitch_cached/cached/log.h#2 edit .. //depot/projects/soc2005/nsswitch_cached/cached/protocol.c#1 add .. //depot/projects/soc2005/nsswitch_cached/cached/protocol.h#1 add .. //depot/projects/soc2005/nsswitch_cached/cached/query.c#2 edit .. //depot/projects/soc2005/nsswitch_cached/cached/query.h#2 edit .. //depot/projects/soc2005/nsswitch_cached/cached/singletons.c#2 edit .. //depot/projects/soc2005/nsswitch_cached/cached/singletons.h#2 edit Differences ... ==== //depot/projects/soc2005/nsswitch_cached/cached/Makefile#2 (text+ko) ==== @@ -4,7 +4,7 @@ PROGNAME=cached MAN= -SRCS=cached.c debug.c log.c config.c query.c singletons.c +SRCS=cached.c debug.c log.c config.c query.c singletons.c protocol.c CFLAGS+= -I${.CURDIR}/../ WARNS?=2 LDADD+=${.CURDIR}/../cachelib/libcachelib.a ==== //depot/projects/soc2005/nsswitch_cached/cached/cached.c#2 (text+ko) ==== @@ -1,5 +1,15 @@ #include <cachelib/include/cachelib.h> +#include <sys/event.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/un.h> +#include <assert.h> +#include <errno.h> +#include <fcntl.h> #include <stdio.h> +#include <string.h> +#include <unistd.h> #include "config.h" #include "debug.h" #include "log.h" @@ -15,7 +25,7 @@ } static cache -init_cache_(void) +init_cache_(struct configuration *config) { struct cache_params params; cache retval; @@ -38,22 +48,201 @@ TRACE_OUT(destroy_cache_); } +static struct runtime_env * +init_runtime_env(struct configuration *config) +{ + int serv_addr_len; + struct sockaddr_un serv_addr; + + struct kevent eventlist; + struct timespec timeout; + + struct runtime_env *retval; + + TRACE_IN(init_runtime_env); + retval = (struct runtime_env *)malloc(sizeof(struct runtime_env)); + assert(retval != NULL); + memset(retval, 0, sizeof(struct runtime_env)); + + retval->sockfd = socket(PF_LOCAL, SOCK_STREAM, 0); + + if (config->force_unlink == 1) + unlink(config->socket_path); + + memset(&serv_addr, 0, sizeof(struct sockaddr_un)); + serv_addr.sun_family = PF_LOCAL; + strncpy(serv_addr.sun_path, config->socket_path, sizeof(serv_addr.sun_path)); + serv_addr_len = sizeof(serv_addr.sun_family) + strlen(serv_addr.sun_path) + 1; + + if (bind(retval->sockfd, (struct sockaddr *)&serv_addr, serv_addr_len) == -1) { + TRACE_INT(errno); + close(retval->sockfd); + free(retval); + + TRACE_OUT(init_runtime_env); + return (NULL); + } + chmod(config->socket_path, config->socket_mode); + listen(retval->sockfd, 100); + fcntl(retval->sockfd, F_SETFL, O_NONBLOCK); + + retval->queue = kqueue(); + assert(retval->queue != -1); + + EV_SET(&eventlist, retval->sockfd, EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, 0); + memset(&timeout, 0, sizeof(struct timespec)); + kevent(retval->queue, &eventlist, 1, NULL, 0, &timeout); + + TRACE_OUT(init_runtime_env); + return (retval); +} + static void -processing_loop(cache the_cache) +destroy_runtime_env(struct runtime_env *env) +{ + TRACE_IN(destroy_runtime_env); + close(env->queue); + close(env->sockfd); + free(env); + TRACE_OUT(destroy_runtime_env); +} + +static void +accept_connection(struct kevent *event_data, struct runtime_env *env, + struct configuration *config) +{ + struct kevent eventlist[2]; + struct timespec timeout; + struct query_state *qstate; + + struct sockaddr addr; + size_t addr_len; + int fd; + + TRACE_IN(accept_connection); + addr_len = sizeof(struct sockaddr); + fd = accept(event_data->ident, &addr, &addr_len); + if (fd == -1) { + /* do something */ + } + + qstate = init_query_state(fd, sizeof(int)); + memset(&timeout, 0, sizeof(struct timespec)); + + EV_SET(&eventlist[0], fd, EVFILT_READ, EV_ADD | EV_ONESHOT, + NOTE_LOWAT, qstate->kevent_watermark, qstate); + EV_SET(&eventlist[1], fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, + 0, config->query_timeout, qstate); + kevent(env->queue, eventlist, 2, NULL, 0, &timeout); + + TRACE_OUT(accept_connection); +} + +static void +process_socket_event(struct kevent *event_data, struct runtime_env *env, + struct configuration *config) +{ + struct kevent eventlist[1]; + struct timespec timeout; + int nevents; + + TRACE_IN(process_socket_event); + memset(&timeout, 0, sizeof(struct timespec)); + EV_SET(&eventlist[0], event_data->ident, EVFILT_TIMER, EV_DELETE, + 0, 0, NULL); + nevents = kevent(env->queue, eventlist, 1, NULL, 0, &timeout); + if (nevents == -1) { + if (errno == ENOENT) { + /* the timer is already handling this event */ + return; + } else { + /* some other error happened */ + return; + } + } + + TRACE_OUT(process_socket_event); +} + +static void +process_timer_event(struct kevent *event_data, struct runtime_env *env, + struct configuration *config) +{ + struct query_state *qstate; + + TRACE_IN(process_timer_event); + qstate = (struct query_state *)event_data->udata; + destroy_query_state(qstate); + TRACE_OUT(process_timer_event); +} + +static void +processing_loop(cache the_cache, struct runtime_env *env, + struct configuration *config) { + struct timespec timeout; + const int eventlist_size = 1; + struct kevent eventlist[eventlist_size]; + int nevents; + TRACE_IN(processing_loop); + memset(&timeout, 0, sizeof(struct timespec)); + memset(&eventlist, 0, sizeof(struct kevent) * eventlist_size); + + for (;;) { + nevents = kevent(env->queue, NULL, 0, eventlist, eventlist_size, NULL); + + if (nevents == 1) { + struct kevent *event_data; + event_data = &eventlist[0]; + + if (event_data->ident == env->sockfd) + accept_connection(event_data, env, config); + else { + switch (event_data->filter) { + case EVFILT_READ: + case EVFILT_WRITE: + process_socket_event(event_data, env, config); + break; + case EVFILT_TIMER: + process_timer_event(event_data, env, config); + break; + default: + break; + } + } + } else { + /* this branch shouldn't be currently executed */ + } + } + TRACE_OUT(processing_loop); } int main(int argc, char *argv[]) { + /* startup output */ print_version_info(); + + /* configuration initialization */ s_configuration = init_configuration(); - s_cache = init_cache_(); + fill_configuration_defaults(s_configuration); + + /* cache initialization */ + s_cache = init_cache_(s_configuration); + + /* runtime environment initialization */ + s_runtime_env = init_runtime_env(s_configuration); + + processing_loop(s_cache, s_runtime_env, s_configuration); - processing_loop(s_cache); + /* runtime environment destruction */ + destroy_runtime_env(s_runtime_env); + /* cache destruction */ destroy_cache_(s_cache); + + /* configuration destruction */ destroy_configuration(s_configuration); return (0); } ==== //depot/projects/soc2005/nsswitch_cached/cached/config.c#2 (text+ko) ==== @@ -5,7 +5,7 @@ #include <string.h> #include "debug.h" -#define DEFAULT_SOCKET_PATH "/var/run/cached" +#define DEFAULT_SOCKET_PATH "/tmp/cached" struct configuration * init_configuration(void) @@ -36,6 +36,13 @@ assert(config->socket_path != NULL); memset(config->socket_path, 0, def_sockpath_len); memcpy(config->socket_path, DEFAULT_SOCKET_PATH, def_sockpath_len); + + config->socket_mode = S_IFSOCK | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | + S_IROTH | S_IWOTH; + config->force_unlink = 1; + + config->query_timeout = 8000; + TRACE_OUT(fill_configuration_defaults); } ==== //depot/projects/soc2005/nsswitch_cached/cached/config.h#2 (text+ko) ==== @@ -1,9 +1,15 @@ #ifndef __CACHED_CONFIG_H__ #define __CACHED_CONFIG_H__ +#include <sys/stat.h> + /* the cached configuration parameters */ struct configuration { - char *socket_path; + char *socket_path; + mode_t socket_mode; + int force_unlink; + + int query_timeout; }; struct configuration *init_configuration(void); ==== //depot/projects/soc2005/nsswitch_cached/cached/debug.c#2 (text+ko) ==== ==== //depot/projects/soc2005/nsswitch_cached/cached/debug.h#2 (text+ko) ==== ==== //depot/projects/soc2005/nsswitch_cached/cached/log.c#2 (text+ko) ==== ==== //depot/projects/soc2005/nsswitch_cached/cached/log.h#2 (text+ko) ==== ==== //depot/projects/soc2005/nsswitch_cached/cached/query.c#2 (text+ko) ==== @@ -1,1 +1,315 @@ #include "query.h" +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/event.h> +#include <assert.h> +#include <stdlib.h> +#include <string.h> +#include "debug.h" +#include "log.h" + +static int on_query_startup(struct query_state *); +static void on_query_destroy(struct query_state *); + +static int on_write_request_read1(struct query_state *); +static int on_write_request_read2(struct query_state *); +static int on_write_request_process(struct query_state *); +static int on_write_response_write1(struct query_state *); + +static int on_read_request_read1(struct query_state *); +static int on_read_request_read2(struct query_state *); +//static int on_read_request_process(struct query_state *); +//static int on_read_response_write1(struct query_state *); +//static int on_read_response_write2(struct query_state *); + +static int on_transform_request_read1(struct query_state *); +//static int on_transform_request_process(struct query_state *); +//static int on_transform_response_write(struct query_state *); + +static int +on_query_startup(struct query_state *qstate) +{ + struct msghdr cred_hdr; + struct iovec iov; + int elem_type; + + struct { + struct cmsghdr hdr; + struct cmsgcred creds; + } cmsg; + + TRACE_IN(on_query_startup); + assert(qstate != NULL); + assert(qstate != NULL); + + memset(&cred_hdr, 0, sizeof(struct msghdr)); + cred_hdr.msg_iov = &iov; + cred_hdr.msg_iovlen = 1; + cred_hdr.msg_control = &cmsg; + cred_hdr.msg_controllen = sizeof(cmsg); + + memset(&iov, 0, sizeof(struct iovec)); + iov.iov_base = &elem_type; + iov.iov_len = sizeof(int); + + if (recvmsg(qstate->sockfd, &cred_hdr, 0) == -1) { + TRACE_OUT(on_query_startup); + return (-1); + } + + if (cmsg.hdr.cmsg_len != sizeof cmsg + || cmsg.hdr.cmsg_level != SOL_SOCKET + || cmsg.hdr.cmsg_type != SCM_CREDS) { + TRACE_OUT(on_query_startup); + return (-1); + } + + qstate->uid = cmsg.creds.cmcred_uid; + qstate->euid = cmsg.creds.cmcred_euid; + qstate->pid = cmsg.creds.cmcred_pid; + + switch (elem_type) { + case CET_WRITE_REQUEST: + qstate->process_func = on_write_request_read1; + break; + case CET_READ_REQUEST: + qstate->process_func = on_read_request_read1; + break; + case CET_TRANSFORM_REQUEST: + qstate->process_func = on_transform_request_read1; + break; + default: + elem_type = -1; + break; + } + + qstate->kevent_watermark = 0; + TRACE_OUT(on_query_startup); + return (0); +} + +static void +on_query_destroy(struct query_state *qstate) +{ + TRACE_IN(on_query_destroy); + finalize_comm_element(&qstate->response); + finalize_comm_element(&qstate->request); + TRACE_OUT(on_query_destroy); +} + +static int +on_write_request_read1(struct query_state *qstate) +{ + struct cache_write_request *write_request; + ssize_t result; + + TRACE_IN(on_write_request_read1); + if (qstate->kevent_watermark == 0) + qstate->kevent_watermark = sizeof(size_t) * 3; + else { + init_comm_element(&qstate->request, CET_WRITE_REQUEST); + write_request = get_cache_write_request(&qstate->request); + + result = qstate->read_func(qstate, &write_request->entry_length, sizeof(size_t)); + result += qstate->read_func(qstate, &write_request->cache_key_length, sizeof(size_t)); + result += qstate->read_func(qstate, &write_request->data_size, sizeof(size_t)); + + if (result != sizeof(size_t) * 3) { + TRACE_OUT(on_write_request_read1); + return (-1); + } + + if ((write_request->entry_length == 0) || + (write_request->cache_key_length == 0) || + (write_request->data_size == 0)) { + TRACE_OUT(on_write_request_read1); + return (-1); + } + + write_request->entry = (char *)malloc(write_request->entry_length + 1); + assert(write_request->entry != NULL); + memset(write_request->entry, 0, write_request->entry_length + 1); + + write_request->cache_key = (char *)malloc(write_request->cache_key_length + 1); + assert(write_request->cache_key != NULL); + memset(write_request->cache_key, 0, write_request->cache_key_length + 1); + + write_request->data = (char *)malloc(write_request->data_size); + assert(write_request->data != NULL); + memset(write_request->data, 0, write_request->data_size); + + qstate->kevent_watermark = write_request->entry_length + + write_request->cache_key_length + write_request->data_size; + qstate->process_func = on_write_request_read2; + } + + TRACE_OUT(on_write_request_read1); + return (0); +} + +static int +on_write_request_read2(struct query_state *qstate) +{ + struct cache_write_request *write_request; + ssize_t result; + + TRACE_IN(on_write_request_read2); + write_request = get_cache_write_request(&qstate->request); + + result = qstate->read_func(qstate, write_request->entry, write_request->entry_length); + result += qstate->read_func(qstate, write_request->cache_key, write_request->cache_key_length); + result += qstate->read_func(qstate, write_request->data, write_request->data_size); + + if (result != qstate->kevent_watermark) { + TRACE_OUT(on_write_request_read2); + return (-1); + } + + qstate->kevent_watermark = 0; + qstate->process_func = on_write_request_process; + TRACE_OUT(on_write_request_read2); + return (0); +} + +static int +on_write_request_process(struct query_state *qstate) +{ + TRACE_IN(on_write_request_process); + init_comm_element(&qstate->response, CET_WRITE_RESPONSE); + + qstate->kevent_watermark = sizeof(int); + qstate->process_func = on_write_response_write1; + TRACE_OUT(on_write_request_process); + return (0); +} + +static int +on_write_response_write1(struct query_state *qstate) +{ + struct cache_write_response *write_response; + ssize_t result; + + TRACE_IN(on_write_response_write1); + write_response = get_cache_write_response(&qstate->response); + result = qstate->write_func(qstate, &write_response->error_code, sizeof(int)); + if (result != sizeof(int)) { + TRACE_OUT(on_write_response_write1); + return (-1); + } + + qstate->kevent_watermark = 0; + qstate->process_func = NULL; + TRACE_OUT(on_write_response_write1); + return (0); +} + +static int +on_read_request_read1(struct query_state *qstate) +{ + struct cache_read_request *read_request; + ssize_t result; + + TRACE_IN(on_read_request_read1); + if (qstate->kevent_watermark == 0) + qstate->kevent_watermark = sizeof(size_t) * 2; + else { + init_comm_element(&qstate->request, CET_READ_REQUEST); + read_request = get_cache_read_request(&qstate->request); + + result = qstate->read_func(qstate, &read_request->entry_length, sizeof(size_t)); + result += qstate->read_func(qstate, &read_request->cache_key_length, sizeof(size_t)); + + if (result != sizeof(size_t) * 2) { + TRACE_OUT(on_read_request_read1); + return (-1); + } + + read_request->entry = (char *)malloc(read_request->entry_length + 1); + assert(read_request->entry != NULL); + memset(read_request->entry, 0, read_request->entry_length + 1); + + read_request->cache_key = (char *)malloc(read_request->cache_key_length + 1); + assert(read_request->cache_key != NULL); + memset(read_request->cache_key, 0, read_request->cache_key_length + 1); + + qstate->kevent_watermark = read_request->entry_length + + read_request->cache_key_length; + qstate->process_func = on_read_request_read2; + } + + TRACE_OUT(on_read_request_read1); + return (0); +} + +static int +on_read_request_read2(struct query_state *qstate) +{ + return (-1); +} + +static int +on_transform_request_read1(struct query_state *qstate) +{ + TRACE_IN(on_transform_request_read1); + TRACE_OUT(on_transform_request_read1); + return (-1); +} + +ssize_t +query_socket_read(struct query_state *qstate, void *buf, size_t nbytes) +{ + ssize_t result; + + TRACE_IN(query_socket_read); + result = read(qstate->sockfd, buf, nbytes); + TRACE_OUT(query_socket_read); + + return (result); +} + +ssize_t +query_socket_write(struct query_state *qstate, const void *buf, size_t nbytes) +{ + ssize_t result; + + TRACE_IN(query_socket_write); + result = write(qstate->sockfd, buf, nbytes); + TRACE_OUT(query_socket_write); + + return (result); +} + +struct query_state * +init_query_state(int sockfd, size_t kevent_watermark) +{ + struct query_state *retval; + + TRACE_IN(init_query_state); + retval = (struct query_state *)malloc(sizeof(struct query_state)); + assert(retval != NULL); + memset(retval, 0, sizeof(struct query_state)); + + retval->sockfd = sockfd; + retval->kevent_filter = EVFILT_READ; + retval->kevent_watermark = kevent_watermark; + + init_comm_element(&retval->request, CET_UNDEFINED); + init_comm_element(&retval->response, CET_UNDEFINED); + retval->process_func = on_query_startup; + retval->destroy_func = on_query_destroy; + + retval->write_func = query_socket_write; + retval->read_func = query_socket_read; + + TRACE_OUT(init_query_state); + return (retval); +} + +void +destroy_query_state(struct query_state *qstate) +{ + TRACE_IN(destroy_query_state); + free(qstate); + TRACE_OUT(destroy_query_state); +} ==== //depot/projects/soc2005/nsswitch_cached/cached/query.h#2 (text+ko) ==== @@ -1,17 +1,44 @@ #ifndef __CACHED_QUERY_H__ #define __CACHED_QUERY_H__ +#include <sys/types.h> #include <stdlib.h> +#include <unistd.h> +#include "protocol.h" + +struct query_state; +typedef int (*query_process_func)(struct query_state *); +typedef void (*query_destroy_func)(struct query_state *); +typedef ssize_t (*query_read_func)(struct query_state *, void *, size_t); +typedef ssize_t (*query_write_func)(struct query_state *, const void *, size_t); + /* the query state structure contains the information to process all types of * requests and to send all types of responses */ struct query_state { int sockfd; /* the unix socket to read/write */ int kevent_filter; /* EVFILT_READ or EVFILT_WRITE */ size_t kevent_watermark; /* how many bytes do we want to be sent/received */ + + query_process_func process_func; /* called on each event */ + query_destroy_func destroy_func; /* called on destroy */ + + query_write_func write_func; /* data write function */ + query_read_func read_func; /* data read function */ + + struct comm_element request; + struct comm_element response; + void *mdata; + + uid_t euid; /* euid of the caller, recevied via credentials */ + uid_t uid; /* uid of the caller, recevied via credentials */ + pid_t pid; /* pid of the caller, recevied via credentials */ }; -struct query_state *init_query_state(int); +ssize_t query_socket_read(struct query_state *, void *, size_t); +ssize_t query_socket_write(struct query_state *, const void *, size_t); + +struct query_state *init_query_state(int, size_t); void destroy_query_state(struct query_state *); #endif ==== //depot/projects/soc2005/nsswitch_cached/cached/singletons.c#2 (text+ko) ==== @@ -2,3 +2,4 @@ struct configuration *s_configuration = NULL; cache s_cache; /* TODO: initializer needed? */ +struct runtime_env *s_runtime_env = NULL; ==== //depot/projects/soc2005/nsswitch_cached/cached/singletons.h#2 (text+ko) ==== @@ -4,7 +4,13 @@ #include <cachelib/include/cachelib.h> #include "config.h" +struct runtime_env { + int queue; + int sockfd; +}; + extern struct configuration *s_configuration; extern cache s_cache; +extern struct runtime_env *s_runtime_env; #endif
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200508041143.j74BhJ5K074641>