diff options
| author | Vikas Gorur <vikas@zresearch.com> | 2009-02-18 17:36:07 +0530 | 
|---|---|---|
| committer | Vikas Gorur <vikas@zresearch.com> | 2009-02-18 17:36:07 +0530 | 
| commit | 77adf4cd648dce41f89469dd185deec6b6b53a0b (patch) | |
| tree | 02e155a5753b398ee572b45793f889b538efab6b /mod_glusterfs/apache/1.3/src/mod_glusterfs.c | |
| parent | f3b2e6580e5663292ee113c741343c8a43ee133f (diff) | |
Added all files
Diffstat (limited to 'mod_glusterfs/apache/1.3/src/mod_glusterfs.c')
| -rw-r--r-- | mod_glusterfs/apache/1.3/src/mod_glusterfs.c | 514 | 
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 000000000..e13d77626 --- /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 +};  | 
