summaryrefslogtreecommitdiffstats
path: root/mod_glusterfs/apache/1.3/src/mod_glusterfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'mod_glusterfs/apache/1.3/src/mod_glusterfs.c')
-rw-r--r--mod_glusterfs/apache/1.3/src/mod_glusterfs.c514
1 files changed, 514 insertions, 0 deletions
diff --git a/mod_glusterfs/apache/1.3/src/mod_glusterfs.c b/mod_glusterfs/apache/1.3/src/mod_glusterfs.c
new file mode 100644
index 00000000000..e13d7762679
--- /dev/null
+++ b/mod_glusterfs/apache/1.3/src/mod_glusterfs.c
@@ -0,0 +1,514 @@
+/*
+ Copyright (c) 2008 Z RESEARCH, Inc. <http://www.zresearch.com>
+ This file is part of GlusterFS.
+
+ GlusterFS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3 of the License,
+ or (at your option) any later version.
+
+ GlusterFS is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef CORE_PRIVATE
+#define CORE_PRIVATE
+#endif
+
+#include <httpd.h>
+#include <http_config.h>
+#include <http_core.h>
+#include <http_request.h>
+#include <http_protocol.h>
+#include <http_log.h>
+#include <http_main.h>
+#include <util_script.h>
+#include <libglusterfsclient.h>
+#include <sys/uio.h>
+#include <pthread.h>
+
+#define GLUSTERFS_INVALID_LOGLEVEL "mod_glusterfs: Unrecognized log-level \"%s\", possible values are \"DEBUG|WARNING|ERROR|CRITICAL|NONE\"\n"
+
+#define GLUSTERFS_HANDLER "glusterfs-handler"
+#define GLUSTERFS_CHUNK_SIZE 131072
+
+module MODULE_VAR_EXPORT glusterfs_module;
+
+/*TODO: verify error returns to server core */
+
+typedef struct glusterfs_dir_config {
+ char *logfile;
+ char *loglevel;
+ char *specfile;
+ char *mount_dir;
+ char *buf;
+ size_t xattr_file_size;
+ uint32_t cache_timeout;
+ libglusterfs_handle_t handle;
+} glusterfs_dir_config_t;
+
+typedef struct glusterfs_async_local {
+ int op_ret;
+ int op_errno;
+ char async_read_complete;
+ off_t length;
+ off_t read_bytes;
+ glusterfs_read_buf_t *buf;
+ request_rec *request;
+ pthread_mutex_t lock;
+ pthread_cond_t cond;
+}glusterfs_async_local_t;
+
+#define GLUSTERFS_CMD_PERMS ACCESS_CONF
+
+static glusterfs_dir_config_t *
+mod_glusterfs_dconfig(request_rec *r)
+{
+ glusterfs_dir_config_t *dir_config = NULL;
+ if (r->per_dir_config != NULL) {
+ dir_config = ap_get_module_config (r->per_dir_config, &glusterfs_module);
+ }
+
+ return dir_config;
+}
+
+static
+const char *add_xattr_file_size(cmd_parms *cmd, void *dummy, char *arg)
+{
+ glusterfs_dir_config_t *dir_config = dummy;
+ dir_config->xattr_file_size = atoi (arg);
+ return NULL;
+}
+
+static
+const char *set_cache_timeout(cmd_parms *cmd, void *dummy, char *arg)
+{
+ glusterfs_dir_config_t *dir_config = dummy;
+ dir_config->cache_timeout = atoi (arg);
+ return NULL;
+}
+
+static
+const char *set_loglevel(cmd_parms *cmd, void *dummy, char *arg)
+{
+ glusterfs_dir_config_t *dir_config = dummy;
+ char *error = NULL;
+ if (strncasecmp (arg, "DEBUG", strlen ("DEBUG"))
+ && strncasecmp (arg, "WARNING", strlen ("WARNING"))
+ && strncasecmp (arg, "CRITICAL", strlen ("CRITICAL"))
+ && strncasecmp (arg, "NONE", strlen ("NONE"))
+ && strncasecmp (arg, "ERROR", strlen ("ERROR")))
+ error = GLUSTERFS_INVALID_LOGLEVEL;
+ else
+ dir_config->loglevel = arg;
+
+ return error;
+}
+
+static
+const char *add_logfile(cmd_parms *cmd, void *dummy, char *arg)
+{
+ glusterfs_dir_config_t *dir_config = dummy;
+ dir_config->logfile = arg;
+
+ return NULL;
+}
+
+static
+const char *add_specfile(cmd_parms *cmd, void *dummy, char *arg)
+{
+ glusterfs_dir_config_t *dir_config = dummy;
+
+ dir_config->specfile = arg;
+
+ return NULL;
+}
+
+static void *
+mod_glusterfs_create_dir_config(pool *p, char *dirspec)
+{
+ glusterfs_dir_config_t *dir_config = NULL;
+
+ dir_config = (glusterfs_dir_config_t *) ap_pcalloc(p, sizeof(*dir_config));
+
+ dir_config->mount_dir = dirspec;
+ dir_config->logfile = dir_config->specfile = (char *)0;
+ dir_config->loglevel = "warning";
+ dir_config->handle = (libglusterfs_handle_t) 0;
+ dir_config->cache_timeout = 0;
+ dir_config->buf = NULL;
+
+ return (void *) dir_config;
+}
+
+static void
+mod_glusterfs_child_init(server_rec *s, pool *p)
+{
+ void **urls = NULL;
+ int n, i;
+ core_server_config *mod_core_config = ap_get_module_config (s->module_config,
+ &core_module);
+ glusterfs_dir_config_t *dir_config = NULL;
+ glusterfs_init_ctx_t ctx;
+
+ n = mod_core_config->sec_url->nelts;
+ urls = (void **)mod_core_config->sec_url->elts;
+ for (i = 0; i < n; i++) {
+ dir_config = ap_get_module_config (urls[i], &glusterfs_module);
+
+ if (dir_config) {
+ memset (&ctx, 0, sizeof (ctx));
+
+ ctx.logfile = dir_config->logfile;
+ ctx.loglevel = dir_config->loglevel;
+ ctx.lookup_timeout = ctx.stat_timeout = dir_config->cache_timeout;
+ ctx.specfile = dir_config->specfile;
+
+ dir_config->handle = glusterfs_init (&ctx);
+ }
+ dir_config = NULL;
+ }
+}
+
+static void
+mod_glusterfs_child_exit(server_rec *s, pool *p)
+{
+ void **urls = NULL;
+ int n, i;
+ core_server_config *mod_core_config = ap_get_module_config (s->module_config,
+ &core_module);
+ glusterfs_dir_config_t *dir_config = NULL;
+
+ n = mod_core_config->sec_url->nelts;
+ urls = (void **)mod_core_config->sec_url->elts;
+ for (i = 0; i < n; i++) {
+ dir_config = ap_get_module_config (urls[i], &glusterfs_module);
+ if (dir_config && dir_config->handle) {
+ glusterfs_fini (dir_config->handle);
+ dir_config->handle = 0;
+ }
+ dir_config = NULL;
+ }
+}
+
+static int mod_glusterfs_fixup(request_rec *r)
+{
+ glusterfs_dir_config_t *dir_config = NULL;
+ int access_status;
+ int ret;
+ char *path = NULL;
+
+ dir_config = mod_glusterfs_dconfig(r);
+
+ if (dir_config && dir_config->mount_dir && !(strncmp (ap_pstrcat (r->pool, dir_config->mount_dir, "/", NULL), r->uri, strlen (dir_config->mount_dir) + 1) && !r->handler))
+ r->handler = ap_pstrdup (r->pool, GLUSTERFS_HANDLER);
+
+ if (!r->handler || (r->handler && strcmp (r->handler, GLUSTERFS_HANDLER)))
+ return DECLINED;
+
+ if (dir_config->mount_dir)
+ path = r->uri + strlen (dir_config->mount_dir);
+
+ memset (&r->finfo, 0, sizeof (r->finfo));
+
+ dir_config->buf = calloc (1, dir_config->xattr_file_size);
+ if (!dir_config->buf) {
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ ret = glusterfs_lookup (dir_config->handle, path, dir_config->buf,
+ dir_config->xattr_file_size, &r->finfo);
+
+ if (ret == -1 || r->finfo.st_size > dir_config->xattr_file_size || S_ISDIR (r->finfo.st_mode)) {
+ free (dir_config->buf);
+ dir_config->buf = NULL;
+
+ if (ret == -1) {
+ int error = HTTP_NOT_FOUND;
+ char *emsg = NULL;
+ if (r->path_info == NULL) {
+ emsg = ap_pstrcat(r->pool, strerror (errno), r->filename, NULL);
+ }
+ else {
+ emsg = ap_pstrcat(r->pool, strerror (errno), r->filename, r->path_info, NULL);
+ }
+ ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, r, "%s", emsg);
+ if (errno != ENOENT) {
+ error = HTTP_INTERNAL_SERVER_ERROR;
+ }
+ return error;
+ }
+ }
+
+ if (r->uri && strlen (r->uri) && r->uri[strlen(r->uri) - 1] == '/')
+ r->handler = NULL;
+
+ r->filename = ap_pstrcat (r->pool, r->filename, r->path_info, NULL);
+
+ if ((access_status = ap_find_types(r)) != 0) {
+ return DECLINED;
+ }
+
+ return OK;
+}
+
+
+int
+mod_glusterfs_readv_async_cbk (glusterfs_read_buf_t *buf,
+ void *cbk_data)
+{
+ glusterfs_async_local_t *local = cbk_data;
+
+ pthread_mutex_lock (&local->lock);
+ {
+ local->async_read_complete = 1;
+ local->buf = buf;
+ pthread_cond_signal (&local->cond);
+ }
+ pthread_mutex_unlock (&local->lock);
+
+ return 0;
+}
+
+/* use read_async just to avoid memcpy of read buffer in libglusterfsclient */
+static int
+mod_glusterfs_read_async (request_rec *r, int fd, off_t offset, off_t length)
+{
+ glusterfs_async_local_t local;
+ off_t end;
+ int nbytes;
+ int complete;
+ pthread_cond_init (&local.cond, NULL);
+ pthread_mutex_init (&local.lock, NULL);
+
+ memset (&local, 0, sizeof (local));
+ local.request = r;
+
+ if (length > 0)
+ end = offset + length;
+
+ do {
+ glusterfs_read_buf_t *buf;
+ int i;
+ if (length > 0) {
+ nbytes = end - offset;
+ if (nbytes > GLUSTERFS_CHUNK_SIZE)
+ nbytes = GLUSTERFS_CHUNK_SIZE;
+ } else
+ nbytes = GLUSTERFS_CHUNK_SIZE;
+
+ glusterfs_read_async(fd,
+ nbytes,
+ offset,
+ mod_glusterfs_readv_async_cbk,
+ (void *)&local);
+
+ pthread_mutex_lock (&local.lock);
+ {
+ while (!local.async_read_complete) {
+ pthread_cond_wait (&local.cond, &local.lock);
+ }
+
+ local.op_ret = local.buf->op_ret;
+ local.op_errno = local.buf->op_errno;
+
+ local.async_read_complete = 0;
+ buf = local.buf;
+
+ if (length < 0)
+ complete = (local.buf->op_ret <= 0);
+ else {
+ local.read_bytes += local.buf->op_ret;
+ complete = ((local.read_bytes == length) || (local.buf->op_ret < 0));
+ }
+ }
+ pthread_mutex_unlock (&local.lock);
+
+ for (i = 0; i < buf->count; i++) {
+ if (ap_rwrite (buf->vector[i].iov_base, buf->vector[i].iov_len, r) < 0) {
+ local.op_ret = -1;
+ complete = 1;
+ break;
+ }
+ }
+
+ glusterfs_free (buf);
+
+ offset += nbytes;
+ } while (!complete);
+
+ return (local.op_ret < 0 ? SERVER_ERROR : OK);
+}
+
+/* TODO: to read blocks of size "length" from offset "offset" */
+/*
+ static int
+ mod_glusterfs_read_sync (request_rec *r, int fd, off_t offset, off_t length)
+ {
+ int error = OK;
+ off_t read_bytes;
+ char buf [GLUSTERFS_CHUNK_SIZE];
+
+ while ((read_bytes = glusterfs_read (fd, buf, GLUSTERFS_CHUNK_SIZE)) && read_bytes != -1) {
+ ap_rwrite (buf, read_bytes, r);
+ }
+ if (read_bytes) {
+ error = SERVER_ERROR;
+ }
+ return error;
+ }
+*/
+
+static int
+mod_glusterfs_handler(request_rec *r)
+{
+ glusterfs_dir_config_t *dir_config;
+ char *path = NULL;
+ int error = OK;
+ int rangestatus = 0;
+ int errstatus = OK;
+ int fd;
+
+ if (!r->handler || (r->handler && strcmp (r->handler, GLUSTERFS_HANDLER)))
+ return DECLINED;
+
+ if (r->uri[0] == '\0' || r->uri[strlen(r->uri) - 1] == '/') {
+ return DECLINED;
+ }
+
+ dir_config = mod_glusterfs_dconfig (r);
+
+ if (r->method_number != M_GET) {
+ return METHOD_NOT_ALLOWED;
+ }
+
+ if (!dir_config->handle) {
+ ap_log_rerror (APLOG_MARK, APLOG_ERR, r,
+ "glusterfs initialization failed\n");
+ return FORBIDDEN;
+ }
+
+ ap_update_mtime(r, r->finfo.st_mtime);
+ ap_set_last_modified(r);
+ ap_set_etag(r);
+ ap_table_setn(r->headers_out, "Accept-Ranges", "bytes");
+ if (((errstatus = ap_meets_conditions(r)) != OK)
+ || (errstatus = ap_set_content_length(r, r->finfo.st_size))) {
+ return errstatus;
+ }
+ rangestatus = ap_set_byterange(r);
+ ap_send_http_header(r);
+
+ if (r->finfo.st_size <= dir_config->xattr_file_size && dir_config->buf) {
+ if (!r->header_only) {
+ error = OK;
+ ap_log_rerror (APLOG_MARK, APLOG_NOTICE, r,
+ "fetching data from glusterfs through xattr interface\n");
+
+ if (!rangestatus) {
+ if (ap_rwrite (dir_config->buf, r->finfo.st_size, r) < 0) {
+ error = HTTP_INTERNAL_SERVER_ERROR;
+ }
+ } else {
+ long offset, length;
+ while (ap_each_byterange (r, &offset, &length)) {
+ if (ap_rwrite (dir_config->buf + offset, length, r) < 0) {
+ error = HTTP_INTERNAL_SERVER_ERROR;
+ break;
+ }
+ }
+ }
+ }
+
+ free (dir_config->buf);
+ dir_config->buf = NULL;
+
+ return error;
+ }
+
+ path = r->uri + strlen (dir_config->mount_dir);
+ fd = glusterfs_open (dir_config->handle, path , O_RDONLY, 0);
+
+ if (fd == 0) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
+ "file permissions deny server access: %s", r->filename);
+ return FORBIDDEN;
+ }
+
+ if (!r->header_only) {
+ if (!rangestatus) {
+ mod_glusterfs_read_async (r, fd, 0, -1);
+ } else {
+ long offset, length;
+ while (ap_each_byterange(r, &offset, &length)) {
+ mod_glusterfs_read_async (r, fd, offset, length);
+ }
+ }
+ }
+
+ glusterfs_close (fd);
+ return error;
+}
+
+static const command_rec mod_glusterfs_cmds[] =
+{
+ {"GlusterfsLogfile", add_logfile, NULL,
+ GLUSTERFS_CMD_PERMS, TAKE1,
+ "Glusterfs Logfile"},
+ {"GlusterfsLoglevel", set_loglevel, NULL,
+ GLUSTERFS_CMD_PERMS, TAKE1,
+ "Glusterfs Loglevel:anyone of none, critical, error, warning, debug"},
+ {"GlusterfsCacheTimeout", set_cache_timeout, NULL,
+ GLUSTERFS_CMD_PERMS, TAKE1,
+ "Timeout value in seconds for caching lookups and stats"},
+ {"GlusterfsVolumeSpecfile", add_specfile, NULL,
+ GLUSTERFS_CMD_PERMS, TAKE1,
+ "Glusterfs Specfile required to access contents of this directory"},
+ {"GlusterfsXattrFileSize", add_xattr_file_size, NULL,
+ GLUSTERFS_CMD_PERMS, TAKE1,
+ "Maximum size of the file to be fetched using xattr interface of glusterfs"},
+ {NULL}
+};
+
+static const handler_rec mod_glusterfs_handlers[] =
+{
+ {GLUSTERFS_HANDLER, mod_glusterfs_handler},
+ {NULL}
+};
+
+module glusterfs_module =
+{
+ STANDARD_MODULE_STUFF,
+ NULL,
+ mod_glusterfs_create_dir_config, /* per-directory config creator */
+ NULL,
+ NULL, /* server config creator */
+ NULL, /* server config merger */
+ mod_glusterfs_cmds, /* command table */
+ mod_glusterfs_handlers, /* [7] list of handlers */
+ NULL, /* [2] filename-to-URI translation */
+ NULL, /* [5] check/validate user_id */
+ NULL, /* [6] check user_id is valid *here* */
+ NULL, /* [4] check access by host address */
+ NULL, /* [7] MIME type checker/setter */
+ mod_glusterfs_fixup, /* [8] fixups */
+ NULL, /* [10] logger */
+#if MODULE_MAGIC_NUMBER >= 19970103
+ NULL, /* [3] header parser */
+#endif
+#if MODULE_MAGIC_NUMBER >= 19970719
+ mod_glusterfs_child_init, /* process initializer */
+#endif
+#if MODULE_MAGIC_NUMBER >= 19970728
+ mod_glusterfs_child_exit, /* process exit/cleanup */
+#endif
+#if MODULE_MAGIC_NUMBER >= 19970902
+ NULL /* [1] post read_request handling */
+#endif
+};