Built using apr_memcache.
Not hooked up into the build system fully yet.
Add -DHAVE_APR_MEMCACHE to your CFLAGS to build:
./config.nice CFLAGS="-DHAVE_APR_MEMCACHE"
Configuration:
Listen *:443
SSLSessionCache memcache:127.0.0.1:11211
<Virtualhost *:443>
ServerName localhost
SSLEngine on
SSLCertificateFile conf/localhost.crt
SSLCertificateKeyFile conf/localhost.key
</VirtualHost>
Comments welcome.
-Paul
Index: modules/ssl/ssl_private.h
===================================================================
--- modules/ssl/ssl_private.h (revision 355792)
+++ modules/ssl/ssl_private.h (working copy)
@@ -265,6 +265,7 @@
SSL_SCMODE_DBM = 1,
SSL_SCMODE_SHMCB = 3,
SSL_SCMODE_DC = 4,
+ SSL_SCMODE_MC = 5,
SSL_SCMODE_NONE_NOT_NULL = 5
} ssl_scmode_t;
@@ -586,6 +587,13 @@
void ssl_scache_dc_remove(server_rec *, UCHAR *, int);
void ssl_scache_dc_status(request_rec *r, int flags, apr_pool_t *pool);
+void ssl_scache_mc_init(server_rec *, apr_pool_t *);
+void ssl_scache_mc_kill(server_rec *);
+BOOL ssl_scache_mc_store(server_rec *, UCHAR *, int, time_t,
SSL_SESSION *);
+SSL_SESSION *ssl_scache_mc_retrieve(server_rec *, UCHAR *, int);
+void ssl_scache_mc_remove(server_rec *, UCHAR *, int);
+void ssl_scache_mc_status(request_rec *r, int flags, apr_pool_t *pool);
+
/** Proxy Support */
int ssl_proxy_enable(conn_rec *c);
int ssl_engine_disable(conn_rec *c);
Index: modules/ssl/ssl_scache.c
===================================================================
--- modules/ssl/ssl_scache.c (revision 355792)
+++ modules/ssl/ssl_scache.c (working copy)
@@ -59,6 +59,10 @@
else if (mc->nSessionCacheMode == SSL_SCMODE_DC)
ssl_scache_dc_init(s, p);
#endif
+#ifdef HAVE_APR_MEMCACHE
+ else if (mc->nSessionCacheMode == SSL_SCMODE_MC)
+ ssl_scache_mc_init(s, p);
+#endif
else if (mc->nSessionCacheMode == SSL_SCMODE_SHMCB) {
void *data;
const char *userdata_key = "ssl_scache_init";
@@ -85,6 +89,10 @@
else if (mc->nSessionCacheMode == SSL_SCMODE_DC)
ssl_scache_dc_kill(s);
#endif
+#ifdef HAVE_APR_MEMCACHE
+ else if (mc->nSessionCacheMode == SSL_SCMODE_MC)
+ ssl_scache_mc_kill(s);
+#endif
return;
}
@@ -101,6 +109,10 @@
else if (mc->nSessionCacheMode == SSL_SCMODE_DC)
rv = ssl_scache_dc_store(s, id, idlen, expiry, sess);
#endif
+#ifdef HAVE_APR_MEMCACHE
+ else if (mc->nSessionCacheMode == SSL_SCMODE_MC)
+ rv = ssl_scache_mc_store(s, id, idlen, expiry, sess);
+#endif
return rv;
}
@@ -117,6 +129,10 @@
else if (mc->nSessionCacheMode == SSL_SCMODE_DC)
sess = ssl_scache_dc_retrieve(s, id, idlen);
#endif
+#ifdef HAVE_APR_MEMCACHE
+ else if (mc->nSessionCacheMode == SSL_SCMODE_MC)
+ sess = ssl_scache_mc_retrieve(s, id, idlen);
+#endif
return sess;
}
@@ -132,6 +148,10 @@
else if (mc->nSessionCacheMode == SSL_SCMODE_DC)
ssl_scache_dc_remove(s, id, idlen);
#endif
+#ifdef HAVE_DISTCACHE
+ else if (mc->nSessionCacheMode == SSL_SCMODE_MC)
+ ssl_scache_mc_remove(s, id, idlen);
+#endif
return;
}
@@ -162,6 +182,10 @@
else if (sc->mc->nSessionCacheMode == SSL_SCMODE_DC)
ssl_scache_dc_status(r, flags, r->pool);
#endif
+#ifdef HAVE_APR_MEMCACHE
+ else if (sc->mc->nSessionCacheMode == SSL_SCMODE_MC)
+ ssl_scache_mc_status(r, flags, r->pool);
+#endif
ap_rputs("</td></tr>\n", r);
ap_rputs("</table>\n", r);
Index: modules/ssl/ssl_engine_config.c
===================================================================
--- modules/ssl/ssl_engine_config.c (revision 355792)
+++ modules/ssl/ssl_engine_config.c (working copy)
@@ -1072,6 +1072,19 @@
return "SSLSessionCache: distcache support disabled";
#endif
}
+ else if ((arglen > 3) && strcEQn(arg, "memcache:", 9)) {
+#ifdef HAVE_APR_MEMCACHE
+ mc->nSessionCacheMode = SSL_SCMODE_MC;
+ mc->szSessionCacheDataFile = apr_pstrdup(mc->pPool, arg+9);
+ if (!mc->szSessionCacheDataFile) {
+ return apr_pstrcat(cmd->pool,
+ "SSLSessionCache: Invalid memcache config: ",
+ arg+9, NULL);
+ }
+#else
+ return "SSLSessionCache: memcache support disabled";
+#endif
+ }
else {
return "SSLSessionCache: Invalid argument";
}
Index: modules/ssl/config.m4
===================================================================
--- modules/ssl/config.m4 (revision 355792)
+++ modules/ssl/config.m4 (working copy)
@@ -109,6 +109,7 @@
ssl_scache_dbm.lo dnl
ssl_scache_shmcb.lo dnl
ssl_scache_dc.lo dnl
+ssl_scache_memcache.lo dnl
ssl_util.lo dnl
ssl_util_ssl.lo dnl
"
Index: modules/ssl/ssl_scache_memcache.c
===================================================================
--- modules/ssl/ssl_scache_memcache.c (revision 0)
+++ modules/ssl/ssl_scache_memcache.c (revision 0)
@@ -0,0 +1,285 @@
+/* Copyright 2004-2005 The Apache Software Foundation or its licensors, as
+ * applicable.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* _ _
+ * _ __ ___ ___ __| | ___ ___| | mod_ssl
+ * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
+ * | | | | | | (_) | (_| | \__ \__ \ |
+ * |_| |_| |_|\___/ \__,_|___|___/___/_|
+ * |_____|
+ * ssl_scache_dc.c
+ * Distributed Session Cache (client support)
+ */
+
+#include "ssl_private.h"
+
+#ifdef HAVE_APR_MEMCACHE
+
+#include "apr_memcache.h"
+#include "ap_mpm.h"
+
+/*
+ * SSL Session Caching using memcached as a backend.
+ */
+
+/*
+**
+** High-Level "handlers" as per ssl_scache.c
+**
+*/
+
+
+/* The underlying apr_memcache system is thread safe.. */
+static apr_memcache_t* memctxt;
+
+#define MC_TAG "mod_ssl:"
+#define MC_TAG_LEN \
+ (sizeof(MC_TAG))
+
+#define MC_KEY_LEN 254
+
+void ssl_scache_mc_init(server_rec *s, apr_pool_t *p)
+{
+ apr_status_t rv;
+ int thread_limit = 0;
+ int nservers = 0;
+ char* cache_config;
+ char* split;
+ char* tok;
+ SSLModConfigRec *mc = myModConfig(s);
+
+ ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit);
+
+ if (mc->szSessionCacheDataFile == NULL) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "SSLSessionCache required");
+ ssl_die();
+ }
+
+ /* Find all the servers in the first run to get a total count */
+ cache_config = apr_pstrdup(p, mc->szSessionCacheDataFile);
+ split = apr_strtok(cache_config, ",", &tok);
+ while (split) {
+ nservers++;
+ split = apr_strtok(NULL,",", &tok);
+ }
+
+ rv = apr_memcache_create(p, nservers, 0, &memctxt);
+ if (rv != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
+ "SSLSessionCache: Failed to create Memcache Object of
'%d' size.",
+ nservers);
+ ssl_die();
+ }
+
+ /* Now add each server to the memcache */
+ cache_config = apr_pstrdup(p, mc->szSessionCacheDataFile);
+ split = apr_strtok(cache_config, ",", &tok);
+ while (split) {
+ apr_memcache_server_t* st;
+ char* host_str;
+ char* scope_id;
+ apr_port_t port;
+
+ rv = apr_parse_addr_port(&host_str, &scope_id, &port, split, p);
+ if (rv != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
+ "SSLSessionCache: Failed to Parse Server: '%s'",
split);
+ ssl_die();
+ }
+
+ if (host_str == NULL) {
+ ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
+ "SSLSessionCache: Failed to Parse Server, "
+ "no hostname specified: '%s'", split);
+ ssl_die();
+ }
+
+ if (port == 0) {
+ port = 11211; /* default port */
+ }
+
+ /* Should Max Conns be (thread_limit / nservers) ? */
+ rv = apr_memcache_server_create(p,
+ host_str, port,
+ 0,
+ 1,
+ thread_limit,
+ 600,
+ &st);
+ if (rv != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
+ "SSLSessionCache: Failed to Create Server: %s:%d",
+ host_str, port);
+ ssl_die();
+ }
+
+ rv = apr_memcache_add_server(memctxt, st);
+ if (rv != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
+ "SSLSessionCache: Failed to Add Server: %s:%d",
+ host_str, port);
+ ssl_die();
+ }
+
+ split = apr_strtok(NULL,",", &tok);
+ }
+
+ return;
+}
+
+void ssl_scache_mc_kill(server_rec *s)
+{
+
+}
+
+static char *mc_session_id2sz(unsigned char *id, int idlen,
+ char *str, int strsize)
+{
+ char *cp;
+ int n;
+
+ cp = apr_cpystrn(str, MC_TAG, MC_TAG_LEN);
+ for (n = 0; n < idlen && n < (MC_KEY_LEN - MC_TAG_LEN); n++) {
+ apr_snprintf(cp, strsize - (cp-str), "%02X", id[n]);
+ cp += 2;
+ }
+ *cp = '\0';
+ return str;
+}
+
+BOOL ssl_scache_mc_store(server_rec *s, UCHAR *id, int idlen,
+ time_t timeout, SSL_SESSION * pSession)
+{
+ char buf[MC_KEY_LEN];
+ char* strkey = NULL;
+ UCHAR ucaData[SSL_SESSION_MAX_DER];
+ UCHAR *ucp;
+ int nData;
+ apr_status_t rv;
+
+ /* streamline session data */
+ if ((nData = i2d_SSL_SESSION(pSession, NULL)) > sizeof(ucaData)) {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+ "streamline session data size too large: %d > "
+ "%" APR_SIZE_T_FMT,
+ nData, sizeof(ucaData));
+ return FALSE;
+ }
+
+ ucp = ucaData;
+ i2d_SSL_SESSION(pSession, &ucp);
+
+ strkey = mc_session_id2sz(id, idlen, buf, sizeof(buf));
+ if(!strkey) {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "scache_mc: Key generation
borked.");
+ return FALSE;
+ }
+
+ timeout -= time(NULL);
+
+ timeout = apr_time_sec(timeout);
+
+ rv = apr_memcache_set(memctxt, strkey, (char*)ucp, nData, timeout, 0);
+
+ if (rv != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_CRIT, rv,
+ s,
+ "SSLCache/memcache: error setting key '%s' "
+ "with %d bytes of data", strkey, nData);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+SSL_SESSION *ssl_scache_mc_retrieve(server_rec *s, UCHAR *id, int idlen)
+{
+ SSL_SESSION *pSession;
+ MODSSL_D2I_SSL_SESSION_CONST unsigned char *pder;
+ apr_size_t der_len;
+ SSLModConfigRec *mc = myModConfig(s);
+ char buf[MC_KEY_LEN];
+ char* strkey = NULL;
+ apr_status_t rv;
+
+ strkey = mc_session_id2sz(id, idlen, buf, sizeof(buf));
+
+ if(!strkey) {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "scache_mc: Key generation
borked.");
+ return NULL;
+ }
+
+ rv = apr_memcache_getp(memctxt, mc->pPool, strkey,
+ (char**)&pder, &der_len, NULL);
+
+ if (rv == APR_NOTFOUND) {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "memcache scache
'get_session' MISS");
+ return NULL;
+ }
+
+ if (rv != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "memcache scache
'get_session' FAIL");
+ return NULL;
+ }
+
+ if (der_len > SSL_SESSION_MAX_DER) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "memcache scache
'get_session' OVERFLOW");
+ return NULL;
+ }
+
+ pSession = d2i_SSL_SESSION(NULL, &pder, der_len);
+
+ if (!pSession) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "memcache scache
'get_session' CORRUPT");
+ return NULL;
+ }
+
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "memcache scache 'get_session'
HIT");
+
+ return pSession;
+}
+
+void ssl_scache_mc_remove(server_rec *s, UCHAR *id, int idlen)
+{
+ char buf[MC_KEY_LEN];
+ char* strkey = NULL;
+ apr_status_t rv;
+
+ strkey = mc_session_id2sz(id, idlen, buf, sizeof(buf));
+ if(!strkey) {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "scache_mc: Key generation
borked.");
+ return;
+ }
+
+ rv = apr_memcache_delete(memctxt, strkey, 0);
+
+ if (rv != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, rv,
+ s,
+ "memcache scache: error deleting key '%s' ",
+ strkey);
+ return;
+ }
+}
+
+void ssl_scache_mc_status(request_rec *r, int flags, apr_pool_t *pool)
+{
+ /* SSLModConfigRec *mc = myModConfig(r->server); */
+ /* TODO: Make a mod_status handler. meh. */
+}
+
+#endif
+
Property changes on: modules/ssl/ssl_scache_memcache.c
___________________________________________________________________
Name: svn:eol-style
+ native