Move mutex handling up out of the session cache providers:
* modules/ssl/ssl_private.h (modssl_sesscache_provider): Add name and
flags fields. Define MODSSL_SESSCACHE_FLAG_NOTMPSAFE constant.
* modules/ssl/ssl_scache.c (ssl_scache_store, ssl_scache_retrieve,
ssl_scache_remove, ssl_ext_status_hook): Lock and release the mutex
around provider calls, if necessary.
* modules/ssl/ssl_engine_mutex.c (ssl_mutex_init): Do nothing if no
session cache is configured, or the session cache does not require a
mutex. Otherwise, fail if no mutex is configured and the session
cache *does* require a mutex.
(ssl_mutex_on, ssl_mutex_off): Remove checks for mutex mode;
functions now invoked only if necessary.
* modules/ssl/ssl_scache_dc.c, modules/ssl/ssl_scache_memcache: Set
name and flags fields in provider structures.
* modules/ssl/ssl_scache_shmcb.c, modules/ssl_scache_dbm.c: Remove
mutex handling through; set name and flags fields in provider
structures; mark both as unsafe for concurrent access in flags.
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@631297
13f79535-47bb-0310-9956-
ffa450edef68
SSLModConfigRec *mc = myModConfig(s);
apr_status_t rv;
- if (mc->nMutexMode == SSL_MUTEXMODE_NONE)
+ /* A mutex is only needed if a session cache is configured, and
+ * the provider used is not internally multi-process/thread
+ * safe. */
+ if (!mc->sesscache
+ || (mc->sesscache->flags & MODSSL_SESSCACHE_FLAG_NOTMPSAFE) == 0) {
return TRUE;
+ }
if (mc->pMutex) {
return TRUE;
}
+ else if (mc->nMutexMode == SSL_MUTEXMODE_NONE) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
+ "An SSLMutex is required for the '%s' session cache",
+ mc->sesscache->name);
+ return FALSE;
+ }
+
if ((rv = apr_global_mutex_create(&mc->pMutex, mc->szMutexFile,
mc->nMutexMech, s->process->pool))
!= APR_SUCCESS) {
SSLModConfigRec *mc = myModConfig(s);
apr_status_t rv;
- if (mc->nMutexMode == SSL_MUTEXMODE_NONE)
- return TRUE;
if ((rv = apr_global_mutex_lock(mc->pMutex)) != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_WARNING, rv, s,
"Failed to acquire SSL session cache lock");
SSLModConfigRec *mc = myModConfig(s);
apr_status_t rv;
- if (mc->nMutexMode == SSL_MUTEXMODE_NONE)
- return TRUE;
if ((rv = apr_global_mutex_unlock(mc->pMutex)) != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_WARNING, rv, s,
"Failed to release SSL session cache lock");
#define MODSSL_SESSCACHE_PROVIDER_GROUP "mod_ssl-sesscache"
#define MODSSL_SESSCACHE_PROVIDER_VERSION "0"
+/* If this flag is set, the store/retrieve/delete/status interfaces of
+ * the provider are NOT safe to be called concurrently from multiple
+ * processes or threads, and an external global mutex must be used to
+ * serialize access to the provider. */
+#define MODSSL_SESSCACHE_FLAG_NOTMPSAFE (0x0001)
+
/* Session cache provider vtable. */
typedef struct {
+ /* Canonical provider name: */
+ const char *name;
+
+ /* Bitmask of MODSSL_SESSCACHE_FLAG_* flags: */
+ unsigned int flags;
+
/* Create a session cache based on the given configuration string
* ARG. Returns NULL on success, or an error string on failure.
* Pool TMP should be used for any temporary allocations, pool P
SSLModConfigRec *mc = myModConfig(s);
unsigned char encoded[SSL_SESSION_MAX_DER], *ptr;
unsigned int len;
+ BOOL rv;
/* Serialise the session. */
len = i2d_SSL_SESSION(sess, NULL);
ptr = encoded;
len = i2d_SSL_SESSION(sess, &ptr);
- return mc->sesscache->store(mc->sesscache_context, s, id, idlen,
- expiry, encoded, len);
+ if (mc->sesscache->flags & MODSSL_SESSCACHE_FLAG_NOTMPSAFE) {
+ ssl_mutex_on(s);
+ }
+
+ rv = mc->sesscache->store(mc->sesscache_context, s, id, idlen,
+ expiry, encoded, len);
+
+ if (mc->sesscache->flags & MODSSL_SESSCACHE_FLAG_NOTMPSAFE) {
+ ssl_mutex_off(s);
+ }
+
+ return rv;
}
SSL_SESSION *ssl_scache_retrieve(server_rec *s, UCHAR *id, int idlen,
unsigned char dest[SSL_SESSION_MAX_DER];
unsigned int destlen = SSL_SESSION_MAX_DER;
MODSSL_D2I_SSL_SESSION_CONST unsigned char *ptr;
-
- if (mc->sesscache->retrieve(mc->sesscache_context, s, id, idlen,
- dest, &destlen, p) == FALSE) {
+ BOOL rv;
+
+ if (mc->sesscache->flags & MODSSL_SESSCACHE_FLAG_NOTMPSAFE) {
+ ssl_mutex_on(s);
+ }
+
+ rv = mc->sesscache->retrieve(mc->sesscache_context, s, id, idlen,
+ dest, &destlen, p);
+
+ if (mc->sesscache->flags & MODSSL_SESSCACHE_FLAG_NOTMPSAFE) {
+ ssl_mutex_off(s);
+ }
+
+ if (rv == FALSE) {
return NULL;
}
{
SSLModConfigRec *mc = myModConfig(s);
+ if (mc->sesscache->flags & MODSSL_SESSCACHE_FLAG_NOTMPSAFE) {
+ ssl_mutex_on(s);
+ }
+
mc->sesscache->delete(mc->sesscache_context, s, id, idlen, p);
- return;
+ if (mc->sesscache->flags & MODSSL_SESSCACHE_FLAG_NOTMPSAFE) {
+ ssl_mutex_off(s);
+ }
}
/* _________________________________________________________________
ap_rputs("</td></tr>\n", r);
ap_rputs("<tr><td bgcolor=\"#ffffff\">\n", r);
+ if (mc->sesscache->flags & MODSSL_SESSCACHE_FLAG_NOTMPSAFE) {
+ ssl_mutex_on(r->server);
+ }
+
mc->sesscache->status(mc->sesscache_context, r, flags, r->pool);
+ if (mc->sesscache->flags & MODSSL_SESSCACHE_FLAG_NOTMPSAFE) {
+ ssl_mutex_off(r->server);
+ }
+
ap_rputs("</td></tr>\n", r);
ap_rputs("</table>\n", r);
return OK;
}
/* open it once to create it and to make sure it _can_ be created */
- ssl_mutex_on(s);
apr_pool_clear(ctx->pool);
if ((rv = apr_dbm_open(&dbm, ctx->data_file,
ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
"Cannot create SSLSessionCache DBM file `%s'",
ctx->data_file);
- ssl_mutex_off(s);
return rv;
}
apr_dbm_close(dbm);
}
}
#endif
- ssl_mutex_off(s);
ssl_scache_dbm_expire(ctx, s);
return APR_SUCCESS;
memcpy((char *)dbmval.dptr+sizeof(time_t), ucaData, nData);
/* and store it to the DBM file */
- ssl_mutex_on(s);
apr_pool_clear(ctx->pool);
if ((rv = apr_dbm_open(&dbm, ctx->data_file,
"Cannot open SSLSessionCache DBM file `%s' for writing "
"(store)",
ctx->data_file);
- ssl_mutex_off(s);
free(dbmval.dptr);
return FALSE;
}
"Cannot store SSL session to DBM file `%s'",
ctx->data_file);
apr_dbm_close(dbm);
- ssl_mutex_off(s);
free(dbmval.dptr);
return FALSE;
}
apr_dbm_close(dbm);
- ssl_mutex_off(s);
/* free temporary buffers */
free(dbmval.dptr);
* XXX: Should we open the dbm against r->pool so the cleanup will
* do the apr_dbm_close? This would make the code a bit cleaner.
*/
- ssl_mutex_on(s);
apr_pool_clear(ctx->pool);
if ((rc = apr_dbm_open(&dbm, ctx->data_file, APR_DBM_RWCREATE,
SSL_DBM_FILE_MODE, ctx->pool)) != APR_SUCCESS) {
"Cannot open SSLSessionCache DBM file `%s' for reading "
"(fetch)",
ctx->data_file);
- ssl_mutex_off(s);
return FALSE;
}
rc = apr_dbm_fetch(dbm, dbmkey, &dbmval);
if (rc != APR_SUCCESS) {
apr_dbm_close(dbm);
- ssl_mutex_off(s);
return FALSE;
}
if (dbmval.dptr == NULL || dbmval.dsize <= sizeof(time_t)) {
apr_dbm_close(dbm);
- ssl_mutex_off(s);
return FALSE;
}
nData = dbmval.dsize-sizeof(time_t);
if (nData > *destlen) {
apr_dbm_close(dbm);
- ssl_mutex_off(s);
return FALSE;
}
memcpy(dest, (char *)dbmval.dptr + sizeof(time_t), nData);
apr_dbm_close(dbm);
- ssl_mutex_off(s);
/* make sure the stuff is still not expired */
now = time(NULL);
dbmkey.dsize = idlen;
/* and delete it from the DBM file */
- ssl_mutex_on(s);
apr_pool_clear(ctx->pool);
if ((rv = apr_dbm_open(&dbm, ctx->data_file, APR_DBM_RWCREATE,
"Cannot open SSLSessionCache DBM file `%s' for writing "
"(delete)",
ctx->data_file);
- ssl_mutex_off(s);
return;
}
apr_dbm_delete(dbm, dbmkey);
apr_dbm_close(dbm);
- ssl_mutex_off(s);
return;
}
*/
tNow = time(NULL);
- ssl_mutex_on(s);
-
if (tNow < ctx->last_expiry + sc->session_cache_timeout) {
- ssl_mutex_off(s);
return;
}
if (keyidx < KEYMAX)
break;
}
- ssl_mutex_off(s);
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
"Inter-Process Session Cache (DBM) Expiry: "
nElem = 0;
nSize = 0;
- ssl_mutex_on(r->server);
apr_pool_clear(ctx->pool);
if ((rv = apr_dbm_open(&dbm, ctx->data_file, APR_DBM_RWCREATE,
"Cannot open SSLSessionCache DBM file `%s' for status "
"retrival",
ctx->data_file);
- ssl_mutex_off(r->server);
return;
}
/*
nSize += dbmval.dsize;
}
apr_dbm_close(dbm);
- ssl_mutex_off(r->server);
if (nSize > 0 && nElem > 0)
nAverage = nSize / nElem;
else
}
const modssl_sesscache_provider modssl_sesscache_dbm = {
+ "dbm",
+ MODSSL_SESSCACHE_FLAG_NOTMPSAFE,
ssl_scache_dbm_create,
ssl_scache_dbm_init,
ssl_scache_dbm_kill,
}
const modssl_sesscache_provider modssl_sesscache_dc = {
+ "distcache",
+ 0,
ssl_scache_dc_create,
ssl_scache_dc_init,
ssl_scache_dc_kill,
}
const modssl_sesscache_provider modssl_sesscache_mc = {
+ "memcache",
+ 0,
ssl_scache_mc_create,
ssl_scache_mc_init,
ssl_scache_mc_kill,
unsigned char *encoded,
unsigned int len_encoded)
{
- BOOL to_return = FALSE;
struct context *ctx = context;
SHMCBHeader *header = ctx->header;
SHMCBSubcache *subcache = SHMCB_MASK(header, id);
- ssl_mutex_on(s);
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
"ssl_scache_shmcb_store (0x%02x -> subcache %d)",
SHMCB_MASK_DBG(header, id));
if (idlen < 4) {
ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "unusably short session_id provided "
"(%u bytes)", idlen);
- goto done;
+ return FALSE;
}
if (!shmcb_subcache_store(s, header, subcache, encoded,
len_encoded, id, idlen, timeout)) {
ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
"can't store a session!");
- goto done;
+ return FALSE;
}
header->stat_stores++;
- to_return = TRUE;
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
"leaving ssl_scache_shmcb_store successfully");
-done:
- ssl_mutex_off(s);
- return to_return;
+ return TRUE;
}
static BOOL ssl_scache_shmcb_retrieve(void *context, server_rec *s,
SHMCBSubcache *subcache = SHMCB_MASK(header, id);
BOOL rv;
- ssl_mutex_on(s);
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
"ssl_scache_shmcb_retrieve (0x%02x -> subcache %d)",
SHMCB_MASK_DBG(header, id));
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
"leaving ssl_scache_shmcb_retrieve successfully");
- ssl_mutex_off(s);
return rv;
}
SHMCBHeader *header = ctx->header;
SHMCBSubcache *subcache = SHMCB_MASK(header, id);
- ssl_mutex_on(s);
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
"ssl_scache_shmcb_remove (0x%02x -> subcache %d)",
SHMCB_MASK_DBG(header, id));
if (idlen < 4) {
ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "unusably short session_id provided "
"(%u bytes)", idlen);
- goto done;
+ return;
}
if (shmcb_subcache_remove(s, header, subcache, id, idlen))
header->stat_removes_hit++;
header->stat_removes_miss++;
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
"leaving ssl_scache_shmcb_remove successfully");
-done:
- ssl_mutex_off(s);
}
static void ssl_scache_shmcb_status(void *context, request_rec *r,
/* Perform the iteration inside the mutex to avoid corruption or invalid
* pointer arithmetic. The rest of our logic uses read-only header data so
* doesn't need the lock. */
- ssl_mutex_on(s);
/* Iterate over the subcaches */
for (loop = 0; loop < header->subcache_num; loop++) {
SHMCBSubcache *subcache = SHMCB_SUBCACHE(header, loop);
min_expiry = ((idx_expiry < min_expiry) ? idx_expiry : min_expiry);
}
}
- ssl_mutex_off(s);
index_pct = (100 * total) / (header->index_num *
header->subcache_num);
cache_pct = (100 * cache_total) / (header->subcache_data_size *
}
const modssl_sesscache_provider modssl_sesscache_shmcb = {
+ "shmcb",
+ MODSSL_SESSCACHE_FLAG_NOTMPSAFE,
ssl_scache_shmcb_create,
ssl_scache_shmcb_init,
ssl_scache_shmcb_kill,