1/* Licensed to the Apache Software Foundation (ASF) under one or more 2 * contributor license agreements. See the NOTICE file distributed with 3 * this work for additional information regarding copyright ownership. 4 * The ASF licenses this file to You under the Apache License, Version 2.0 5 * (the "License"); you may not use this file except in compliance with 6 * the License. You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "httpd.h" 18#include "http_log.h" 19#include "http_request.h" 20#include "http_config.h" 21#include "http_protocol.h" 22 23#include "apr_strings.h" 24#include "apr_time.h" 25 26#include "ap_socache.h" 27 28#include "distcache/dc_client.h" 29 30#if !defined(DISTCACHE_CLIENT_API) || (DISTCACHE_CLIENT_API < 0x0001) 31#error "You must compile with a more recent version of the distcache-base package" 32#endif 33 34struct ap_socache_instance_t { 35 /* Configured target server: */ 36 const char *target; 37 /* distcache client context: */ 38 DC_CTX *dc; 39}; 40 41static const char *socache_dc_create(ap_socache_instance_t **context, 42 const char *arg, 43 apr_pool_t *tmp, apr_pool_t *p) 44{ 45 struct ap_socache_instance_t *ctx; 46 47 ctx = *context = apr_palloc(p, sizeof *ctx); 48 49 ctx->target = apr_pstrdup(p, arg); 50 51 return NULL; 52} 53 54static apr_status_t socache_dc_init(ap_socache_instance_t *ctx, 55 const char *namespace, 56 const struct ap_socache_hints *hints, 57 server_rec *s, apr_pool_t *p) 58{ 59#if 0 60 /* If a "persistent connection" mode of operation is preferred, you *must* 61 * also use the PIDCHECK flag to ensure fork()'d processes don't interlace 62 * comms on the same connection as each other. */ 63#define SESSION_CTX_FLAGS SESSION_CTX_FLAG_PERSISTENT | \ 64 SESSION_CTX_FLAG_PERSISTENT_PIDCHECK | \ 65 SESSION_CTX_FLAG_PERSISTENT_RETRY | \ 66 SESSION_CTX_FLAG_PERSISTENT_LATE 67#else 68 /* This mode of operation will open a temporary connection to the 'target' 69 * for each cache operation - this makes it safe against fork() 70 * automatically. This mode is preferred when running a local proxy (over 71 * unix domain sockets) because overhead is negligable and it reduces the 72 * performance/stability danger of file-descriptor bloatage. */ 73#define SESSION_CTX_FLAGS 0 74#endif 75 ctx->dc = DC_CTX_new(ctx->target, SESSION_CTX_FLAGS); 76 if (!ctx->dc) { 77 ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(00738) "distributed scache failed to obtain context"); 78 return APR_EGENERAL; 79 } 80 ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(00739) "distributed scache context initialised"); 81 82 return APR_SUCCESS; 83} 84 85static void socache_dc_destroy(ap_socache_instance_t *ctx, server_rec *s) 86{ 87 if (ctx && ctx->dc) { 88 DC_CTX_free(ctx->dc); 89 ctx->dc = NULL; 90 } 91} 92 93static apr_status_t socache_dc_store(ap_socache_instance_t *ctx, server_rec *s, 94 const unsigned char *id, unsigned int idlen, 95 apr_time_t expiry, 96 unsigned char *der, unsigned int der_len, 97 apr_pool_t *p) 98{ 99 /* !@#$%^ - why do we deal with *absolute* time anyway??? 100 * Uhm - because most things expire things at a specific time? 101 * Were the API were thought out expiry - r->request_time is a good approximation 102 */ 103 expiry -= apr_time_now(); 104 /* Send the serialised session to the distributed cache context */ 105 if (!DC_CTX_add_session(ctx->dc, id, idlen, der, der_len, 106 apr_time_msec(expiry))) { 107 ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(00740) "distributed scache 'store' failed"); 108 return APR_EGENERAL; 109 } 110 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00741) "distributed scache 'store' successful"); 111 return APR_SUCCESS; 112} 113 114static apr_status_t socache_dc_retrieve(ap_socache_instance_t *ctx, server_rec *s, 115 const unsigned char *id, unsigned int idlen, 116 unsigned char *dest, unsigned int *destlen, 117 apr_pool_t *p) 118{ 119 unsigned int data_len; 120 121 /* Retrieve any corresponding session from the distributed cache context */ 122 if (!DC_CTX_get_session(ctx->dc, id, idlen, dest, *destlen, &data_len)) { 123 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00742) "distributed scache 'retrieve' MISS"); 124 return APR_NOTFOUND; 125 } 126 if (data_len > *destlen) { 127 ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(00743) "distributed scache 'retrieve' OVERFLOW"); 128 return APR_ENOSPC; 129 } 130 *destlen = data_len; 131 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00744) "distributed scache 'retrieve' HIT"); 132 return APR_SUCCESS; 133} 134 135static apr_status_t socache_dc_remove(ap_socache_instance_t *ctx, 136 server_rec *s, const unsigned char *id, 137 unsigned int idlen, apr_pool_t *p) 138{ 139 /* Remove any corresponding session from the distributed cache context */ 140 if (!DC_CTX_remove_session(ctx->dc, id, idlen)) { 141 ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(00745) "distributed scache 'remove' MISS"); 142 return APR_NOTFOUND; 143 } 144 else { 145 ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(00746) "distributed scache 'remove' HIT"); 146 return APR_SUCCESS; 147 } 148} 149 150static void socache_dc_status(ap_socache_instance_t *ctx, request_rec *r, int flags) 151{ 152 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00747) 153 "distributed scache 'socache_dc_status'"); 154 ap_rprintf(r, "cache type: <b>DC (Distributed Cache)</b>, " 155 " target: <b>%s</b><br>", ctx->target); 156} 157 158static apr_status_t socache_dc_iterate(ap_socache_instance_t *instance, 159 server_rec *s, void *userctx, 160 ap_socache_iterator_t *iterator, 161 apr_pool_t *pool) 162{ 163 return APR_ENOTIMPL; 164} 165 166static const ap_socache_provider_t socache_dc = { 167 "distcache", 168 0, 169 socache_dc_create, 170 socache_dc_init, 171 socache_dc_destroy, 172 socache_dc_store, 173 socache_dc_retrieve, 174 socache_dc_remove, 175 socache_dc_status, 176 socache_dc_iterate 177}; 178 179static void register_hooks(apr_pool_t *p) 180{ 181 ap_register_provider(p, AP_SOCACHE_PROVIDER_GROUP, "dc", 182 AP_SOCACHE_PROVIDER_VERSION, 183 &socache_dc); 184} 185 186AP_DECLARE_MODULE(socache_dc) = { 187 STANDARD20_MODULE_STUFF, 188 NULL, NULL, NULL, NULL, NULL, 189 register_hooks 190}; 191 192