PERFORCE change 81439 for review
soc-bushman
soc-bushman at FreeBSD.org
Thu Aug 4 11:43:21 GMT 2005
http://perforce.freebsd.org/chv.cgi?CH=81439
Change 81439 by soc-bushman at 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
More information about the p4-projects
mailing list