summaryrefslogtreecommitdiff
path: root/modules/ssl/ssl_scache_shmcb.c
diff options
context:
space:
mode:
Diffstat (limited to 'modules/ssl/ssl_scache_shmcb.c')
-rw-r--r--modules/ssl/ssl_scache_shmcb.c1343
1 files changed, 0 insertions, 1343 deletions
diff --git a/modules/ssl/ssl_scache_shmcb.c b/modules/ssl/ssl_scache_shmcb.c
deleted file mode 100644
index e588f0a5d1..0000000000
--- a/modules/ssl/ssl_scache_shmcb.c
+++ /dev/null
@@ -1,1343 +0,0 @@
-/* _ _
-** _ __ ___ ___ __| | ___ ___| | mod_ssl
-** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
-** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org
-** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org
-** |_____|
-** ssl_scache_shmcb.c
-** Session Cache via Shared Memory (Cyclic Buffer Variant)
-*/
-
-/* ====================================================================
- * Copyright (c) 2000-2001 Ralf S. Engelschall. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by
- * Ralf S. Engelschall <rse@engelschall.com> for use in the
- * mod_ssl project (http://www.modssl.org/)."
- *
- * 4. The names "mod_ssl" must not be used to endorse or promote
- * products derived from this software without prior written
- * permission. For written permission, please contact
- * rse@engelschall.com.
- *
- * 5. Products derived from this software may not be called "mod_ssl"
- * nor may "mod_ssl" appear in their names without prior
- * written permission of Ralf S. Engelschall.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by
- * Ralf S. Engelschall <rse@engelschall.com> for use in the
- * mod_ssl project (http://www.modssl.org/)."
- *
- * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RALF S. ENGELSCHALL OR
- * HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- * ====================================================================
- */
-
-#include "mod_ssl.h"
-
-/*
- * This shared memory based SSL session cache implementation was
- * originally written by Geoff Thorpe <geoff@eu.c2.net> for C2Net Europe
- * and as a contribution to Ralf Engelschall's mod_ssl project.
- */
-
-/*
- * The shared-memory segment header can be cast to and from the
- * SHMCBHeader type, all other structures need to be initialised by
- * utility functions.
- *
- * The "header" looks like this;
- *
- * data applying to the overall structure:
- * - division_offset (unsigned int):
- * how far into the shared memory segment the first division is.
- * - division_size (unsigned int):
- * how many bytes each division occupies.
- * (NB: This includes the queue and the cache)
- * - division_mask (unsigned char):
- * the "mask" in the next line. Add one to this,
- * and that's the number of divisions.
- *
- * data applying to within each division:
- * - queue_size (unsigned int):
- * how big each "queue" is. NB: The queue is the first block in each
- * division and is followed immediately by the cache itself so so
- * there's no cache_offset value.
- *
- * data applying to within each queue:
- * - index_num (unsigned char):
- * how many indexes in each cache's queue
- * - index_offset (unsigned char):
- * how far into the queue the first index is.
- * - index_size:
- * how big each index is.
- *
- * data applying to within each cache:
- * - cache_data_offset (unsigned int):
- * how far into the cache the session-data array is stored.
- * - cache_data_size (unsigned int):
- * how big each cache's data block is.
- *
- * statistics data (this will eventually be per-division but right now
- * there's only one mutex):
- * - stores (unsigned long):
- * how many stores have been performed in the cache.
- * - expiries (unsigned long):
- * how many session have been expired from the cache.
- * - scrolled (unsigned long):
- * how many sessions have been scrolled out of full cache during a
- * "store" operation. This is different to the "removes" stats as
- * they are requested by mod_ssl/Apache, these are done because of
- * cache logistics. (NB: Also, this value should be deducible from
- * the others if my code has no bugs, but I count it anyway - plus
- * it helps debugging :-).
- * - retrieves_hit (unsigned long):
- * how many session-retrieves have succeeded.
- * - retrieves_miss (unsigned long):
- * how many session-retrieves have failed.
- * - removes_hit (unsigned long):
- * - removes_miss (unsigned long):
- *
- * Following immediately after the header is an array of "divisions".
- * Each division is simply a "queue" immediately followed by its
- * corresponding "cache". Each division handles some pre-defined band
- * of sessions by using the "division_mask" in the header. Eg. if
- * division_mask=0x1f then there are 32 divisions, the first of which
- * will store sessions whose least-significant 5 bits are 0, the second
- * stores session whose LS 5 bits equal 1, etc. A queue is an indexing
- * structure referring to its corresponding cache.
- *
- * A "queue" looks like this;
- *
- * - first_pos (unsigned int):
- * the location within the array of indexes where the virtual
- * "left-hand-edge" of the cyclic buffer is.
- * - pos_count (unsigned int):
- * the number of indexes occupied from first_pos onwards.
- *
- * ...followed by an array of indexes, each of which can be
- * memcpy'd to and from an SHMCBIndex, and look like this;
- *
- * - expires (time_t):
- * the time() value at which this session expires.
- * - offset (unsigned int):
- * the offset within the cache data block where the corresponding
- * session is stored.
- * - s_id2 (unsigned char):
- * the second byte of the session_id, stored as an optimisation to
- * reduce the number of d2i_SSL_SESSION calls that are made when doing
- * a lookup.
- * - removed (unsigned char):
- * a byte used to indicate whether a session has been "passively"
- * removed. Ie. it is still in the cache but is to be disregarded by
- * any "retrieve" operation.
- *
- * A "cache" looks like this;
- *
- * - first_pos (unsigned int):
- * the location within the data block where the virtual
- * "left-hand-edge" of the cyclic buffer is.
- * - pos_count (unsigned int):
- * the number of bytes used in the data block from first_pos onwards.
- *
- * ...followed by the data block in which actual DER-encoded SSL
- * sessions are stored.
- */
-
-/*
- * Header - can be memcpy'd to and from the front of the shared
- * memory segment. NB: The first copy (commented out) has the
- * elements in a meaningful order, but due to data-alignment
- * braindeadness, the second (uncommented) copy has the types grouped
- * so as to decrease "struct-bloat". sigh.
- */
-typedef struct {
-#if 0
- unsigned char division_mask;
- unsigned int division_offset;
- unsigned int division_size;
- unsigned int queue_size;
- unsigned char index_num;
- unsigned char index_offset;
- unsigned char index_size;
- unsigned int cache_data_offset;
- unsigned int cache_data_size;
- unsigned long num_stores;
- unsigned long num_expiries;
- unsigned long num_scrolled;
- unsigned long num_retrieves_hit;
- unsigned long num_retrieves_miss;
- unsigned long num_removes_hit;
- unsigned long num_removes_miss;
-#else
- unsigned long num_stores;
- unsigned long num_expiries;
- unsigned long num_scrolled;
- unsigned long num_retrieves_hit;
- unsigned long num_retrieves_miss;
- unsigned long num_removes_hit;
- unsigned long num_removes_miss;
- unsigned int division_offset;
- unsigned int division_size;
- unsigned int queue_size;
- unsigned int cache_data_offset;
- unsigned int cache_data_size;
- unsigned char division_mask;
- unsigned char index_num;
- unsigned char index_offset;
- unsigned char index_size;
-#endif
-} SHMCBHeader;
-
-/*
- * Index - can be memcpy'd to and from an index inside each
- * queue's index array.
- */
-typedef struct {
- time_t expires;
- unsigned int offset;
- unsigned char s_id2;
- unsigned char removed;
-} SHMCBIndex;
-
-/*
- * Queue - must be populated by a call to shmcb_get_division
- * and the structure's pointers are used for updating (ie.
- * the structure doesn't need any "set" to update values).
- */
-typedef struct {
- SHMCBHeader *header;
- unsigned int *first_pos;
- unsigned int *pos_count;
- SHMCBIndex *indexes;
-} SHMCBQueue;
-
-/*
- * Cache - same comment as for Queue. 'Queue's are in a 1-1
- * correspondance with 'Cache's and are usually carried round
- * in a pair, they are only seperated for clarity.
- */
-typedef struct {
- SHMCBHeader *header;
- unsigned int *first_pos;
- unsigned int *pos_count;
- unsigned char *data;
-} SHMCBCache;
-
-/*
- * Forward function prototypes.
- */
-
-/* Functions for working around data-alignment-picky systems (sparcs,
- Irix, etc). These use "memcpy" as a way of foxing these systems into
- treating the composite types as byte-arrays rather than higher-level
- primitives that it prefers to have 4-(or 8-)byte aligned. I don't
- envisage this being a performance issue as a couple of 2 or 4 byte
- memcpys can hardly make a dent on the massive memmove operations this
- cache technique avoids, nor the overheads of ASN en/decoding. */
-static unsigned int shmcb_get_safe_uint(unsigned int *);
-static void shmcb_set_safe_uint(unsigned int *, unsigned int);
-#if 0 /* Unused so far */
-static unsigned long shmcb_get_safe_ulong(unsigned long *);
-static void shmcb_set_safe_ulong(unsigned long *, unsigned long);
-#endif
-static time_t shmcb_get_safe_time(time_t *);
-static void shmcb_set_safe_time(time_t *, time_t);
-
-/* Underlying functions for session-caching */
-static BOOL shmcb_init_memory(server_rec *, void *, unsigned int);
-static BOOL shmcb_store_session(server_rec *, void *, UCHAR *, int, SSL_SESSION *, time_t);
-static SSL_SESSION *shmcb_retrieve_session(server_rec *, void *, UCHAR *, int);
-static BOOL shmcb_remove_session(server_rec *, void *, UCHAR *, int);
-
-/* Utility functions for manipulating the structures */
-static void shmcb_get_header(void *, SHMCBHeader **);
-static BOOL shmcb_get_division(SHMCBHeader *, SHMCBQueue *, SHMCBCache *, unsigned int);
-static SHMCBIndex *shmcb_get_index(const SHMCBQueue *, unsigned int);
-static unsigned int shmcb_expire_division(server_rec *, SHMCBQueue *, SHMCBCache *);
-static BOOL shmcb_insert_encoded_session(server_rec *, SHMCBQueue *, SHMCBCache *, unsigned char *, unsigned int, unsigned char *, time_t);
-static SSL_SESSION *shmcb_lookup_session_id(server_rec *, SHMCBQueue *, SHMCBCache *, UCHAR *, int);
-static BOOL shmcb_remove_session_id(server_rec *, SHMCBQueue *, SHMCBCache *, UCHAR *, int);
-
-/*
- * Data-alignment functions (a.k.a. avoidance tactics)
- *
- * NB: On HPUX (and possibly others) there is a *very* mischievous little
- * "optimisation" in the compilers where it will convert the following;
- * memcpy(dest_ptr, &source, sizeof(unsigned int));
- * (where dest_ptr is of type (unsigned int *) and source is (unsigned int))
- * into;
- * *dest_ptr = source; (or *dest_ptr = *(&source), not sure).
- * Either way, it completely destroys the whole point of these _safe_
- * functions, because the assignment operation will fall victim to the
- * architecture's byte-alignment dictations, whereas the memcpy (as a
- * byte-by-byte copy) should not. sigh. So, if you're wondering about the
- * apparently unnecessary conversions to (unsigned char *) in these
- * functions, you now have an explanation. Don't just revert them back and
- * say "ooh look, it still works" - if you try it on HPUX (well, 32-bit
- * HPUX 11.00 at least) you may find it fails with a SIGBUS. :-(
- */
-
-static unsigned int shmcb_get_safe_uint(unsigned int *ptr)
-{
- unsigned char *from;
- unsigned int ret;
-
- from = (unsigned char *)ptr;
- memcpy(&ret, from, sizeof(unsigned int));
- return ret;
-}
-
-static void shmcb_set_safe_uint(unsigned int *ptr, unsigned int val)
-{
- unsigned char *to, *from;
-
- to = (unsigned char *)ptr;
- from = (unsigned char *)(&val);
- memcpy(to, from, sizeof(unsigned int));
-}
-
-#if 0 /* Unused so far */
-static unsigned long shmcb_get_safe_ulong(unsigned long *ptr)
-{
- unsigned char *from;
- unsigned long ret;
-
- from = (unsigned char *)ptr;
- memcpy(&ret, from, sizeof(unsigned long));
- return ret;
-}
-
-static void shmcb_set_safe_ulong(unsigned long *ptr, unsigned long val)
-{
- unsigned char *to, *from;
-
- to = (unsigned char *)ptr;
- from = (unsigned char *)(&val);
- memcpy(to, from, sizeof(unsigned long));
-}
-#endif
-
-static time_t shmcb_get_safe_time(time_t * ptr)
-{
- unsigned char *from;
- time_t ret;
-
- from = (unsigned char *)ptr;
- memcpy(&ret, from, sizeof(time_t));
- return ret;
-}
-
-static void shmcb_set_safe_time(time_t * ptr, time_t val)
-{
- unsigned char *to, *from;
-
- to = (unsigned char *)ptr;
- from = (unsigned char *)(&val);
- memcpy(to, from, sizeof(time_t));
-}
-
-/*
-**
-** High-Level "handlers" as per ssl_scache.c
-**
-*/
-
-static void *shmcb_malloc(size_t size)
-{
- SSLModConfigRec *mc = myModConfig();
- return ap_mm_malloc(mc->pSessionCacheDataMM, size);
-}
-
-void ssl_scache_shmcb_init(server_rec *s, pool *p)
-{
- SSLModConfigRec *mc = myModConfig();
- AP_MM *mm;
- void *shm_segment = NULL;
- int avail, avail_orig;
-
- /*
- * Create shared memory segment
- */
- if (mc->szSessionCacheDataFile == NULL) {
- ssl_log(s, SSL_LOG_ERROR, "SSLSessionCache required");
- ssl_die();
- }
- if ((mm = ap_mm_create(mc->nSessionCacheDataSize,
- mc->szSessionCacheDataFile)) == NULL) {
- ssl_log(s, SSL_LOG_ERROR,
- "Cannot allocate shared memory: %s", ap_mm_error());
- ssl_die();
- }
- mc->pSessionCacheDataMM = mm;
-
- /*
- * Make sure the child processes have access to the underlying files
- */
- ap_mm_permission(mm, SSL_MM_FILE_MODE, ap_user_id, -1);
-
- /*
- * Create cache inside the shared memory segment
- */
- avail = avail_orig = ap_mm_available(mm);
- ssl_log(s, SSL_LOG_TRACE, "Shared-memory segment has %u available",
- avail);
-
- /*
- * For some reason to do with MM's internal management, I can't
- * allocate the full amount. Implement a reasonable form of trial
- * and error and output trace information.
- */
- while ((shm_segment == NULL) && ((avail_orig - avail) * 100 < avail_orig)) {
- shm_segment = shmcb_malloc(avail);
- if (shm_segment == NULL) {
- ssl_log(s, SSL_LOG_TRACE,
- "shmcb_malloc attempt for %u bytes failed", avail);
- avail -= 2;
- }
- }
- if (shm_segment == NULL) {
- ssl_log(s, SSL_LOG_ERROR,
- "Cannot allocate memory for the 'shmcb' session cache\n");
- ssl_die();
- }
- ssl_log(s, SSL_LOG_TRACE, "shmcb_init allocated %u bytes of shared "
- "memory", avail);
- if (!shmcb_init_memory(s, shm_segment, avail)) {
- ssl_log(s, SSL_LOG_ERROR,
- "Failure initialising 'shmcb' shared memory");
- ssl_die();
- }
- ssl_log(s, SSL_LOG_INFO, "Shared memory session cache initialised");
-
- /*
- * Success ... we hack the memory block into place by cheating for
- * now and stealing a member variable the original shared memory
- * cache was using. :-)
- */
- mc->tSessionCacheDataTable = (table_t *) shm_segment;
- return;
-}
-
-void ssl_scache_shmcb_kill(server_rec *s)
-{
- SSLModConfigRec *mc = myModConfig();
-
- if (mc->pSessionCacheDataMM != NULL) {
- ap_mm_destroy(mc->pSessionCacheDataMM);
- mc->pSessionCacheDataMM = NULL;
- }
- return;
-}
-
-BOOL ssl_scache_shmcb_store(server_rec *s, UCHAR * id, int idlen,
- time_t timeout, SSL_SESSION * pSession)
-{
- SSLModConfigRec *mc = myModConfig();
- void *shm_segment;
- BOOL to_return = FALSE;
-
- /* We've kludged our pointer into the other cache's member variable. */
- shm_segment = (void *) mc->tSessionCacheDataTable;
- ssl_mutex_on(s);
- if (!shmcb_store_session(s, shm_segment, id, idlen, pSession, timeout))
- /* in this cache engine, "stores" should never fail. */
- ssl_log(s, SSL_LOG_ERROR, "'shmcb' code was unable to store a "
- "session in the cache.");
- else {
- ssl_log(s, SSL_LOG_TRACE, "shmcb_store successful");
- to_return = TRUE;
- }
- ssl_mutex_off(s);
- return to_return;
-}
-
-SSL_SESSION *ssl_scache_shmcb_retrieve(server_rec *s, UCHAR * id, int idlen)
-{
- SSLModConfigRec *mc = myModConfig();
- void *shm_segment;
- SSL_SESSION *pSession;
-
- /* We've kludged our pointer into the other cache's member variable. */
- shm_segment = (void *) mc->tSessionCacheDataTable;
- ssl_mutex_on(s);
- pSession = shmcb_retrieve_session(s, shm_segment, id, idlen);
- ssl_mutex_off(s);
- if (pSession)
- ssl_log(s, SSL_LOG_TRACE, "shmcb_retrieve had a hit");
- else {
- ssl_log(s, SSL_LOG_TRACE, "shmcb_retrieve had a miss");
- ssl_log(s, SSL_LOG_INFO, "Client requested a 'session-resume' but "
- "we have no such session.");
- }
- return pSession;
-}
-
-void ssl_scache_shmcb_remove(server_rec *s, UCHAR * id, int idlen)
-{
- SSLModConfigRec *mc = myModConfig();
- void *shm_segment;
-
- /* We've kludged our pointer into the other cache's member variable. */
- shm_segment = (void *) mc->tSessionCacheDataTable;
- shmcb_remove_session(s, shm_segment, id, idlen);
-}
-
-void ssl_scache_shmcb_expire(server_rec *s)
-{
- /* NOP */
- return;
-}
-
-void ssl_scache_shmcb_status(server_rec *s, pool *p,
- void (*func) (char *, void *), void *arg)
-{
- SSLModConfigRec *mc = myModConfig();
- SHMCBHeader *header;
- SHMCBQueue queue;
- SHMCBCache cache;
- SHMCBIndex *idx;
- void *shm_segment;
- unsigned int loop, total, cache_total, non_empty_divisions;
- int index_pct, cache_pct;
- double expiry_total;
- time_t average_expiry, now, max_expiry, min_expiry, idxexpiry;
-
- ssl_log(s, SSL_LOG_TRACE, "inside ssl_scache_shmcb_status");
-
- /* We've kludged our pointer into the other cache's member variable. */
- shm_segment = (void *) mc->tSessionCacheDataTable;
-
- /* Get the header structure. */
- shmcb_get_header(shm_segment, &header);
- total = cache_total = non_empty_divisions = 0;
- average_expiry = max_expiry = min_expiry = 0;
- expiry_total = 0;
-
- /* It may seem strange to grab "now" at this point, but in theory
- * we should never have a negative threshold but grabbing "now" after
- * the loop (which performs expiries) could allow that chance. */
- now = time(NULL);
- for (loop = 0; loop <= header->division_mask; loop++) {
- if (shmcb_get_division(header, &queue, &cache, loop)) {
- shmcb_expire_division(s, &queue, &cache);
- total += shmcb_get_safe_uint(queue.pos_count);
- cache_total += shmcb_get_safe_uint(cache.pos_count);
- if (shmcb_get_safe_uint(queue.pos_count) > 0) {
- idx = shmcb_get_index(&queue,
- shmcb_get_safe_uint(queue.first_pos));
- non_empty_divisions++;
- idxexpiry = shmcb_get_safe_time(&(idx->expires));
- expiry_total += (double) idxexpiry;
- max_expiry = (idxexpiry > max_expiry ? idxexpiry :
- max_expiry);
- if (min_expiry == 0)
- min_expiry = idxexpiry;
- else
- min_expiry = (idxexpiry < min_expiry ? idxexpiry :
- min_expiry);
- }
- }
- }
- index_pct = (100 * total) / (header->index_num * (header->division_mask + 1));
- cache_pct = (100 * cache_total) / (header->cache_data_size * (header->division_mask + 1));
- func(ap_psprintf(p, "cache type: <b>SHMCB</b>, shared memory: <b>%d</b> "
- "bytes, current sessions: <b>%d</b><br>",
- mc->nSessionCacheDataSize, total), arg);
- func(ap_psprintf(p, "sub-caches: <b>%d</b>, indexes per sub-cache: "
- "<b>%d</b><br>", (int) header->division_mask + 1,
- (int) header->index_num), arg);
- if (non_empty_divisions != 0) {
- average_expiry = (time_t)(expiry_total / (double)non_empty_divisions);
- func(ap_psprintf(p, "time left on oldest entries' SSL sessions: "), arg);
- if (now < average_expiry)
- func(ap_psprintf(p, "avg: <b>%d</b> seconds, (range: %d...%d)<br>",
- (int)(average_expiry - now), (int) (min_expiry - now),
- (int)(max_expiry - now)), arg);
- else
- func(ap_psprintf(p, "expiry threshold: <b>Calculation Error!</b>"
- "<br>"), arg);
-
- }
- func(ap_psprintf(p, "index usage: <b>%d%%</b>, cache usage: <b>%d%%</b>"
- "<br>", index_pct, cache_pct), arg);
- func(ap_psprintf(p, "total sessions stored since starting: <b>%lu</b><br>",
- header->num_stores), arg);
- func(ap_psprintf(p, "total sessions expired since starting: <b>%lu</b><br>",
- header->num_expiries), arg);
- func(ap_psprintf(p, "total (pre-expiry) sessions scrolled out of the "
- "cache: <b>%lu</b><br>", header->num_scrolled), arg);
- func(ap_psprintf(p, "total retrieves since starting: <b>%lu</b> hit, "
- "<b>%lu</b> miss<br>", header->num_retrieves_hit,
- header->num_retrieves_miss), arg);
- func(ap_psprintf(p, "total removes since starting: <b>%lu</b> hit, "
- "<b>%lu</b> miss<br>", header->num_removes_hit,
- header->num_removes_miss), arg);
- ssl_log(s, SSL_LOG_TRACE, "leaving shmcb_status");
- return;
-}
-
-/*
-**
-** Memory manipulation and low-level cache operations
-**
-*/
-
-static BOOL shmcb_init_memory(
- server_rec *s, void *shm_mem,
- unsigned int shm_mem_size)
-{
- SHMCBHeader *header;
- SHMCBQueue queue;
- SHMCBCache cache;
- unsigned int temp, loop, granularity;
-
- ssl_log(s, SSL_LOG_TRACE, "entered shmcb_init_memory()");
-
- /* Calculate some sizes... */
- temp = sizeof(SHMCBHeader);
-
- /* If the segment is ridiculously too small, bail out */
- if (shm_mem_size < (2*temp)) {
- ssl_log(s, SSL_LOG_ERROR, "shared memory segment too small");
- return FALSE;
- }
-
- /* Make temp the amount of memory without the header */
- temp = shm_mem_size - temp;
-
- /* Work on the basis that you need 10 bytes index for each session
- * (approx 150 bytes), which is to divide temp by 160 - and then
- * make sure we err on having too index space to burn even when
- * the cache is full, which is a lot less stupid than having
- * having not enough index space to utilise the whole cache!. */
- temp /= 120;
- ssl_log(s, SSL_LOG_TRACE, "for %u bytes, recommending %u indexes",
- shm_mem_size, temp);
-
- /* We should divide these indexes evenly amongst the queues. Try
- * to get it so that there are roughly half the number of divisions
- * as there are indexes in each division. */
- granularity = 256;
- while ((temp / granularity) < (2 * granularity))
- granularity /= 2;
-
- /* So we have 'granularity' divisions, set 'temp' equal to the
- * number of indexes in each division. */
- temp /= granularity;
-
- /* Too small? Bail ... */
- if (temp < 5) {
- ssl_log(s, SSL_LOG_ERROR, "shared memory segment too small");
- return FALSE;
- }
-
- /* OK, we're sorted - from here on in, the return should be TRUE */
- header = (SHMCBHeader *)shm_mem;
- header->division_mask = (unsigned char)(granularity - 1);
- header->division_offset = sizeof(SHMCBHeader);
- header->index_num = temp;
- header->index_offset = (2 * sizeof(unsigned int));
- header->index_size = sizeof(SHMCBIndex);
- header->queue_size = header->index_offset +
- (header->index_num * header->index_size);
-
- /* Now calculate the space for each division */
- temp = shm_mem_size - header->division_offset;
- header->division_size = temp / granularity;
-
- /* Calculate the space left in each division for the cache */
- temp -= header->queue_size;
- header->cache_data_offset = (2 * sizeof(unsigned int));
- header->cache_data_size = header->division_size -
- header->queue_size - header->cache_data_offset;
-
- /* Output trace info */
- ssl_log(s, SSL_LOG_TRACE, "shmcb_init_memory choices follow");
- ssl_log(s, SSL_LOG_TRACE, "division_mask = 0x%02X", header->division_mask);
- ssl_log(s, SSL_LOG_TRACE, "division_offset = %u", header->division_offset);
- ssl_log(s, SSL_LOG_TRACE, "division_size = %u", header->division_size);
- ssl_log(s, SSL_LOG_TRACE, "queue_size = %u", header->queue_size);
- ssl_log(s, SSL_LOG_TRACE, "index_num = %u", header->index_num);
- ssl_log(s, SSL_LOG_TRACE, "index_offset = %u", header->index_offset);
- ssl_log(s, SSL_LOG_TRACE, "index_size = %u", header->index_size);
- ssl_log(s, SSL_LOG_TRACE, "cache_data_offset = %u", header->cache_data_offset);
- ssl_log(s, SSL_LOG_TRACE, "cache_data_size = %u", header->cache_data_size);
-
- /* The header is done, make the caches empty */
- for (loop = 0; loop < granularity; loop++) {
- if (!shmcb_get_division(header, &queue, &cache, loop))
- ssl_log(s, SSL_LOG_ERROR, "shmcb_init_memory, " "internal error");
- shmcb_set_safe_uint(cache.first_pos, 0);
- shmcb_set_safe_uint(cache.pos_count, 0);
- shmcb_set_safe_uint(queue.first_pos, 0);
- shmcb_set_safe_uint(queue.pos_count, 0);
- }
-
- ssl_log(s, SSL_LOG_TRACE, "leaving shmcb_init_memory()");
- return TRUE;
-}
-
-static BOOL shmcb_store_session(
- server_rec *s, void *shm_segment, UCHAR * id,
- int idlen, SSL_SESSION * pSession,
- time_t timeout)
-{
- SHMCBHeader *header;
- SHMCBQueue queue;
- SHMCBCache cache;
- unsigned char masked_index;
- unsigned char encoded[SSL_SESSION_MAX_DER];
- unsigned char *ptr_encoded;
- unsigned int len_encoded;
- time_t expiry_time;
-
- ssl_log(s, SSL_LOG_TRACE, "inside shmcb_store_session");
-
- /* Get the header structure, which division this session will fall into etc. */
- shmcb_get_header(shm_segment, &header);
- masked_index = pSession->session_id[0] & header->division_mask;
- ssl_log(s, SSL_LOG_TRACE, "session_id[0]=%u, masked index=%u",
- pSession->session_id[0], masked_index);
- if (!shmcb_get_division(header, &queue, &cache, (unsigned int)masked_index)) {
- ssl_log(s, SSL_LOG_ERROR, "shmcb_store_session, " "internal error");
- return FALSE;
- }
-
- /* Serialise the session, work out how much we're dealing
- * with. NB: This check could be removed if we're not paranoid
- * or we find some assurance that it will never be necessary. */
- len_encoded = i2d_SSL_SESSION(pSession, NULL);
- if (len_encoded > SSL_SESSION_MAX_DER) {
- ssl_log(s, SSL_LOG_ERROR, "session is too big (%u bytes)",
- len_encoded);
- return FALSE;
- }
- ptr_encoded = encoded;
- len_encoded = i2d_SSL_SESSION(pSession, &ptr_encoded);
- expiry_time = timeout;
- if (!shmcb_insert_encoded_session(s, &queue, &cache, encoded,
- len_encoded, pSession->session_id,
- expiry_time)) {
- ssl_log(s, SSL_LOG_ERROR, "can't store a session!");
- return FALSE;
- }
- ssl_log(s, SSL_LOG_TRACE, "leaving shmcb_store successfully");
- header->num_stores++;
- return TRUE;
-}
-
-static SSL_SESSION *shmcb_retrieve_session(
- server_rec *s, void *shm_segment,
- UCHAR * id, int idlen)
-{
- SHMCBHeader *header;
- SHMCBQueue queue;
- SHMCBCache cache;
- unsigned char masked_index;
- SSL_SESSION *pSession;
-
- ssl_log(s, SSL_LOG_TRACE, "inside shmcb_retrieve_session");
- if (idlen < 2) {
- ssl_log(s, SSL_LOG_ERROR, "unusably short session_id provided "
- "(%u bytes)", idlen);
- return FALSE;
- }
-
- /* Get the header structure, which division this session lookup
- * will come from etc. */
- shmcb_get_header(shm_segment, &header);
- masked_index = id[0] & header->division_mask;
- ssl_log(s, SSL_LOG_TRACE, "id[0]=%u, masked index=%u", id[0],
- masked_index);
- if (!shmcb_get_division(header, &queue, &cache, (unsigned int) masked_index)) {
- ssl_log(s, SSL_LOG_ERROR, "shmcb_retrieve_session, " "internal error");
- header->num_retrieves_miss++;
- return FALSE;
- }
-
- /* Get the session corresponding to the session_id or NULL if it
- * doesn't exist (or is flagged as "removed"). */
- pSession = shmcb_lookup_session_id(s, &queue, &cache, id, idlen);
- if (pSession)
- header->num_retrieves_hit++;
- else
- header->num_retrieves_miss++;
- ssl_log(s, SSL_LOG_TRACE, "leaving shmcb_retrieve_session");
- return pSession;
-}
-
-static BOOL shmcb_remove_session(
- server_rec *s, void *shm_segment,
- UCHAR * id, int idlen)
-{
- SHMCBHeader *header;
- SHMCBQueue queue;
- SHMCBCache cache;
- unsigned char masked_index;
- BOOL res;
-
- ssl_log(s, SSL_LOG_TRACE, "inside shmcb_remove_session");
- if (id == NULL) {
- ssl_log(s, SSL_LOG_ERROR, "remove called with NULL session_id!");
- return FALSE;
- }
-
- /* Get the header structure, which division this session remove
- * will happen in etc. */
- shmcb_get_header(shm_segment, &header);
- masked_index = id[0] & header->division_mask;
- ssl_log(s, SSL_LOG_TRACE, "id[0]=%u, masked index=%u",
- id[0], masked_index);
- if (!shmcb_get_division(header, &queue, &cache, (unsigned int)masked_index)) {
- ssl_log(s, SSL_LOG_ERROR, "shmcb_remove_session, internal error");
- header->num_removes_miss++;
- return FALSE;
- }
- res = shmcb_remove_session_id(s, &queue, &cache, id, idlen);
- if (res)
- header->num_removes_hit++;
- else
- header->num_removes_miss++;
- ssl_log(s, SSL_LOG_TRACE, "leaving shmcb_remove_session");
- return res;
-}
-
-
-/*
-**
-** Weirdo cyclic buffer functions
-**
-*/
-
-/* This gets used in the cyclic "index array" (in the 'Queue's) and
- * in the cyclic 'Cache's too ... you provide the "width" of the
- * cyclic store, the starting position and how far to move (with
- * wrapping if necessary). Basically it's addition modulo buf_size. */
-static unsigned int shmcb_cyclic_increment(
- unsigned int buf_size,
- unsigned int start_pos,
- unsigned int to_add)
-{
- start_pos += to_add;
- while (start_pos >= buf_size)
- start_pos -= buf_size;
- return start_pos;
-}
-
-/* Given two positions in a cyclic buffer, calculate the "distance".
- * This is to cover the case ("non-trivial") where the 'next' offset
- * is to the left of the 'start' offset. NB: This calculates the
- * space inclusive of one end-point but not the other. There is an
- * ambiguous case (which is why we use the <start_pos,offset>
- * coordinate system rather than <start_pos,end_pos> one) when 'start'
- * is the same as 'next'. It could indicate the buffer is full or it
- * can indicate the buffer is empty ... I choose the latter as it's
- * easier and usually necessary to check if the buffer is full anyway
- * before doing incremental logic (which is this useful for), but we
- * definitely need the empty case handled - in fact it's our starting
- * state!! */
-static unsigned int shmcb_cyclic_space(
- unsigned int buf_size,
- unsigned int start_offset,
- unsigned int next_offset)
-{
- /* Is it the trivial case? */
- if (start_offset <= next_offset)
- return (next_offset - start_offset); /* yes */
- else
- return ((buf_size - start_offset) + next_offset); /* no */
-}
-
-/* A "normal-to-cyclic" memcpy ... this takes a linear block of
- * memory and copies it onto a cyclic buffer. The purpose and
- * function of this is pretty obvious, you need to cover the case
- * that the destination (cyclic) buffer has to wrap round. */
-static void shmcb_cyclic_ntoc_memcpy(
- unsigned int buf_size,
- unsigned char *data,
- unsigned int dest_offset,
- unsigned char *src, unsigned int src_len)
-{
- /* Can it be copied all in one go? */
- if (dest_offset + src_len < buf_size)
- /* yes */
- memcpy(data + dest_offset, src, src_len);
- else {
- /* no */
- memcpy(data + dest_offset, src, buf_size - dest_offset);
- memcpy(data, src + buf_size - dest_offset,
- src_len + dest_offset - buf_size);
- }
- return;
-}
-
-/* A "cyclic-to-normal" memcpy ... given the last function, this
- * one's purpose is clear, it copies out of a cyclic buffer handling
- * wrapping. */
-static void shmcb_cyclic_cton_memcpy(
- unsigned int buf_size,
- unsigned char *dest,
- unsigned char *data,
- unsigned int src_offset,
- unsigned int src_len)
-{
- /* Can it be copied all in one go? */
- if (src_offset + src_len < buf_size)
- /* yes */
- memcpy(dest, data + src_offset, src_len);
- else {
- /* no */
- memcpy(dest, data + src_offset, buf_size - src_offset);
- memcpy(dest + buf_size - src_offset, data,
- src_len + src_offset - buf_size);
- }
- return;
-}
-
-/* Here's the cool hack that makes it all work ... by simply
- * making the first collection of bytes *be* our header structure
- * (casting it into the C structure), we have the perfect way to
- * maintain state in a shared-memory session cache from one call
- * (and process) to the next, use the shared memory itself! The
- * original mod_ssl shared-memory session cache uses variables
- * inside the context, but we simply use that for storing the
- * pointer to the shared memory itself. And don't forget, after
- * Apache's initialisation, this "header" is constant/read-only
- * so we can read it outside any locking.
- * <grin> - sometimes I just *love* coding y'know?! */
-static void shmcb_get_header(void *shm_mem, SHMCBHeader **header)
-{
- *header = (SHMCBHeader *)shm_mem;
- return;
-}
-
-/* This is what populates our "interesting" structures. Given a
- * pointer to the header, and an index into the appropriate
- * division (this must have already been masked using the
- * division_mask by the caller!), we can populate the provided
- * SHMCBQueue and SHMCBCache structures with values and
- * pointers to the underlying shared memory. Upon returning
- * (if not FALSE), the caller can meddle with the pointer
- * values and they will map into the shared-memory directly,
- * as such there's no need to "free" or "set" the Queue or
- * Cache values, they were themselves references to the *real*
- * data. */
-static BOOL shmcb_get_division(
- SHMCBHeader *header, SHMCBQueue *queue,
- SHMCBCache *cache, unsigned int idx)
-{
- unsigned char *pQueue;
- unsigned char *pCache;
-
- /* bounds check */
- if (idx > (unsigned int) header->division_mask)
- return FALSE;
-
- /* Locate the blocks of memory storing the corresponding data */
- pQueue = ((unsigned char *) header) + header->division_offset +
- (idx * header->division_size);
- pCache = pQueue + header->queue_size;
-
- /* Populate the structures with appropriate pointers */
- queue->first_pos = (unsigned int *) pQueue;
-
- /* Our structures stay packed, no matter what the system's
- * data-alignment regime is. */
- queue->pos_count = (unsigned int *) (pQueue + sizeof(unsigned int));
- queue->indexes = (SHMCBIndex *) (pQueue + (2 * sizeof(unsigned int)));
- cache->first_pos = (unsigned int *) pCache;
- cache->pos_count = (unsigned int *) (pCache + sizeof(unsigned int));
- cache->data = (unsigned char *) (pCache + (2 * sizeof(unsigned int)));
- queue->header = cache->header = header;
-
- return TRUE;
-}
-
-/* This returns a pointer to the piece of shared memory containing
- * a specified 'Index'. SHMCBIndex, like SHMCBHeader, is a fixed
- * width non-referencing structure of primitive types that can be
- * cast onto the corresponding block of shared memory. Thus, by
- * returning a cast pointer to that section of shared memory, the
- * caller can read and write values to and from the "structure" and
- * they are actually reading and writing the underlying shared
- * memory. */
-static SHMCBIndex *shmcb_get_index(
- const SHMCBQueue *queue, unsigned int idx)
-{
- /* bounds check */
- if (idx > (unsigned int) queue->header->index_num)
- return NULL;
-
- /* Return a pointer to the index. NB: I am being horribly pendantic
- * here so as to avoid any potential data-alignment assumptions being
- * placed on the pointer arithmetic by the compiler (sigh). */
- return (SHMCBIndex *)(((unsigned char *) queue->indexes) +
- (idx * sizeof(SHMCBIndex)));
-}
-
-/* This functions rolls expired cache (and index) entries off the front
- * of the cyclic buffers in a division. The function returns the number
- * of expired sessions. */
-static unsigned int shmcb_expire_division(
- server_rec *s, SHMCBQueue *queue, SHMCBCache *cache)
-{
- SHMCBIndex *idx;
- time_t now;
- unsigned int loop, index_num, pos_count, new_pos;
- SHMCBHeader *header;
-
- ssl_log(s, SSL_LOG_TRACE, "entering shmcb_expire_division");
-
- /* We must calculate num and space ourselves based on expiry times. */
- now = time(NULL);
- loop = 0;
- new_pos = shmcb_get_safe_uint(queue->first_pos);
-
- /* Cache useful values */
- header = queue->header;
- index_num = header->index_num;
- pos_count = shmcb_get_safe_uint(queue->pos_count);
- while (loop < pos_count) {
- idx = shmcb_get_index(queue, new_pos);
- if (shmcb_get_safe_time(&(idx->expires)) > now)
- /* it hasn't expired yet, we're done iterating */
- break;
- /* This one should be expired too. Shift to the next entry. */
- loop++;
- new_pos = shmcb_cyclic_increment(index_num, new_pos, 1);
- }
-
- /* Find the new_offset and make the expiries happen. */
- if (loop > 0) {
- ssl_log(s, SSL_LOG_TRACE, "will be expiring %u sessions", loop);
- /* We calculate the new_offset by "peeking" (or in the
- * case it's the last entry, "sneaking" ;-). */
- if (loop == pos_count) {
- /* We are expiring everything! This is easy to do... */
- shmcb_set_safe_uint(queue->pos_count, 0);
- shmcb_set_safe_uint(cache->pos_count, 0);
- }
- else {
- /* The Queue is easy to adjust */
- shmcb_set_safe_uint(queue->pos_count,
- shmcb_get_safe_uint(queue->pos_count) - loop);
- shmcb_set_safe_uint(queue->first_pos, new_pos);
- /* peek to the start of the next session */
- idx = shmcb_get_index(queue, new_pos);
- /* We can use shmcb_cyclic_space because we've guaranteed
- * we don't fit the ambiguous full/empty case. */
- shmcb_set_safe_uint(cache->pos_count,
- shmcb_get_safe_uint(cache->pos_count) -
- shmcb_cyclic_space(header->cache_data_size,
- shmcb_get_safe_uint(cache->first_pos),
- shmcb_get_safe_uint(&(idx->offset))));
- shmcb_set_safe_uint(cache->first_pos, shmcb_get_safe_uint(&(idx->offset)));
- }
- ssl_log(s, SSL_LOG_TRACE, "we now have %u sessions",
- shmcb_get_safe_uint(queue->pos_count));
- }
- header->num_expiries += loop;
- return loop;
-}
-
-/* Inserts a new encoded session into a queue/cache pair - expiring
- * (early or otherwise) any leading sessions as necessary to ensure
- * there is room. An error return (FALSE) should only happen in the
- * event of surreal values being passed on, or ridiculously small
- * cache sizes. NB: For tracing purposes, this function is also given
- * the server_rec to allow "ssl_log()". */
-static BOOL shmcb_insert_encoded_session(
- server_rec *s, SHMCBQueue * queue,
- SHMCBCache * cache,
- unsigned char *encoded,
- unsigned int encoded_len,
- unsigned char *session_id,
- time_t expiry_time)
-{
- SHMCBHeader *header;
- SHMCBIndex *idx = NULL;
- unsigned int gap, new_pos, loop, new_offset;
- int need;
-
- ssl_log(s, SSL_LOG_TRACE, "entering shmcb_insert_encoded_session, "
- "*queue->pos_count = %u", shmcb_get_safe_uint(queue->pos_count));
-
- /* If there's entries to expire, ditch them first thing. */
- shmcb_expire_division(s, queue, cache);
- header = cache->header;
- gap = header->cache_data_size - shmcb_get_safe_uint(cache->pos_count);
- if (gap < encoded_len) {
- new_pos = shmcb_get_safe_uint(queue->first_pos);
- loop = 0;
- need = (int) encoded_len - (int) gap;
- while ((need > 0) && (loop + 1 < shmcb_get_safe_uint(queue->pos_count))) {
- new_pos = shmcb_cyclic_increment(header->index_num, new_pos, 1);
- loop += 1;
- idx = shmcb_get_index(queue, new_pos);
- need = (int) encoded_len - (int) gap -
- shmcb_cyclic_space(header->cache_data_size,
- shmcb_get_safe_uint(cache->first_pos),
- shmcb_get_safe_uint(&(idx->offset)));
- }
- if (loop > 0) {
- ssl_log(s, SSL_LOG_TRACE, "about to scroll %u sessions from %u",
- loop, shmcb_get_safe_uint(queue->pos_count));
- /* We are removing "loop" items from the cache. */
- shmcb_set_safe_uint(cache->pos_count,
- shmcb_get_safe_uint(cache->pos_count) -
- shmcb_cyclic_space(header->cache_data_size,
- shmcb_get_safe_uint(cache->first_pos),
- shmcb_get_safe_uint(&(idx->offset))));
- shmcb_set_safe_uint(cache->first_pos, shmcb_get_safe_uint(&(idx->offset)));
- shmcb_set_safe_uint(queue->pos_count, shmcb_get_safe_uint(queue->pos_count) - loop);
- shmcb_set_safe_uint(queue->first_pos, new_pos);
- ssl_log(s, SSL_LOG_TRACE, "now only have %u sessions",
- shmcb_get_safe_uint(queue->pos_count));
- /* Update the stats!!! */
- header->num_scrolled += loop;
- }
- }
-
- /* probably unecessary checks, but I'll leave them until this code
- * is verified. */
- if (shmcb_get_safe_uint(cache->pos_count) + encoded_len >
- header->cache_data_size) {
- ssl_log(s, SSL_LOG_ERROR, "shmcb_insert_encoded_session, "
- "internal error");
- return FALSE;
- }
- if (shmcb_get_safe_uint(queue->pos_count) == header->index_num) {
- ssl_log(s, SSL_LOG_ERROR, "shmcb_insert_encoded_session, "
- "internal error");
- return FALSE;
- }
- ssl_log(s, SSL_LOG_TRACE, "we have %u bytes and %u indexes free - "
- "enough", header->cache_data_size -
- shmcb_get_safe_uint(cache->pos_count), header->index_num -
- shmcb_get_safe_uint(queue->pos_count));
-
-
- /* HERE WE ASSUME THAT THE NEW SESSION SHOULD GO ON THE END! I'M NOT
- * CHECKING WHETHER IT SHOULD BE GENUINELY "INSERTED" SOMEWHERE.
- *
- * We either fix that, or find out at a "higher" (read "mod_ssl")
- * level whether it is possible to have distinct session caches for
- * any attempted tomfoolery to do with different session timeouts.
- * Knowing in advance that we can have a cache-wide constant timeout
- * would make this stuff *MUCH* more efficient. Mind you, it's very
- * efficient right now because I'm ignoring this problem!!!
- */
-
- /* Increment to the first unused byte */
- new_offset = shmcb_cyclic_increment(header->cache_data_size,
- shmcb_get_safe_uint(cache->first_pos),
- shmcb_get_safe_uint(cache->pos_count));
- /* Copy the DER-encoded session into place */
- shmcb_cyclic_ntoc_memcpy(header->cache_data_size, cache->data,
- new_offset, encoded, encoded_len);
- /* Get the new index that this session is stored in. */
- new_pos = shmcb_cyclic_increment(header->index_num,
- shmcb_get_safe_uint(queue->first_pos),
- shmcb_get_safe_uint(queue->pos_count));
- ssl_log(s, SSL_LOG_TRACE, "storing in index %u, at offset %u", new_pos,
- new_offset);
- idx = shmcb_get_index(queue, new_pos);
- if (idx == NULL) {
- ssl_log(s, SSL_LOG_ERROR, "shmcb_insert_encoded_session, "
- "internal error");
- return FALSE;
- }
- memset(idx, 0, sizeof(SHMCBIndex));
- shmcb_set_safe_time(&(idx->expires), expiry_time);
- shmcb_set_safe_uint(&(idx->offset), new_offset);
-
- /* idx->removed = (unsigned char)0; */ /* Not needed given the memset above. */
- idx->s_id2 = session_id[1];
- ssl_log(s, SSL_LOG_TRACE, "session_id[0]=%u, idx->s_id2=%u",
- session_id[0], session_id[1]);
-
- /* All that remains is to adjust the cache's and queue's "pos_count"s. */
- shmcb_set_safe_uint(cache->pos_count,
- shmcb_get_safe_uint(cache->pos_count) + encoded_len);
- shmcb_set_safe_uint(queue->pos_count,
- shmcb_get_safe_uint(queue->pos_count) + 1);
-
- /* And just for good debugging measure ... */
- ssl_log(s, SSL_LOG_TRACE, "leaving now with %u bytes in the cache and "
- "%u indexes", shmcb_get_safe_uint(cache->pos_count),
- shmcb_get_safe_uint(queue->pos_count));
- ssl_log(s, SSL_LOG_TRACE, "leaving shmcb_insert_encoded_session");
- return TRUE;
-}
-
-/* Performs a lookup into a queue/cache pair for a
- * session_id. If found, the session is deserialised
- * and returned, otherwise NULL. */
-static SSL_SESSION *shmcb_lookup_session_id(
- server_rec *s, SHMCBQueue *queue,
- SHMCBCache *cache, UCHAR *id,
- int idlen)
-{
- unsigned char tempasn[SSL_SESSION_MAX_DER];
- SHMCBIndex *idx;
- SHMCBHeader *header;
- SSL_SESSION *pSession = NULL;
- unsigned int curr_pos, loop, count;
- unsigned char *ptr;
- time_t now;
-
- ssl_log(s, SSL_LOG_TRACE, "entering shmcb_lookup_session_id");
-
- /* If there are entries to expire, ditch them first thing. */
- shmcb_expire_division(s, queue, cache);
- now = time(NULL);
- curr_pos = shmcb_get_safe_uint(queue->first_pos);
- count = shmcb_get_safe_uint(queue->pos_count);
- header = queue->header;
- for (loop = 0; loop < count; loop++) {
- ssl_log(s, SSL_LOG_TRACE, "loop=%u, count=%u, curr_pos=%u",
- loop, count, curr_pos);
- idx = shmcb_get_index(queue, curr_pos);
- ssl_log(s, SSL_LOG_TRACE, "idx->s_id2=%u, id[1]=%u, offset=%u",
- idx->s_id2, id[1], shmcb_get_safe_uint(&(idx->offset)));
- /* Only look into the session further if;
- * (a) the second byte of the session_id matches,
- * (b) the "removed" flag isn't set,
- * (c) the session hasn't expired yet.
- * We do (c) like this so that it saves us having to
- * do natural expiries ... naturally expired sessions
- * scroll off the front anyway when the cache is full and
- * "rotating", the only real issue that remains is the
- * removal or disabling of forcibly killed sessions. */
- if ((idx->s_id2 == id[1]) && !idx->removed &&
- (shmcb_get_safe_time(&(idx->expires)) > now)) {
- ssl_log(s, SSL_LOG_TRACE, "at index %u, found possible "
- "session match", curr_pos);
- shmcb_cyclic_cton_memcpy(header->cache_data_size,
- tempasn, cache->data,
- shmcb_get_safe_uint(&(idx->offset)),
- SSL_SESSION_MAX_DER);
- ptr = tempasn;
- pSession = d2i_SSL_SESSION(NULL, &ptr, SSL_SESSION_MAX_DER);
- if (pSession == NULL) {
- ssl_log(s, SSL_LOG_ERROR, "scach2_lookup_"
- "session_id, internal error");
- return NULL;
- }
- if ((pSession->session_id_length == idlen) &&
- (memcmp(pSession->session_id, id, idlen) == 0)) {
- ssl_log(s, SSL_LOG_TRACE, "a match!");
- return pSession;
- }
- ssl_log(s, SSL_LOG_TRACE, "not a match");
- SSL_SESSION_free(pSession);
- pSession = NULL;
- }
- curr_pos = shmcb_cyclic_increment(header->index_num, curr_pos, 1);
- }
- ssl_log(s, SSL_LOG_TRACE, "no matching sessions were found");
- return NULL;
-}
-
-static BOOL shmcb_remove_session_id(
- server_rec *s, SHMCBQueue *queue,
- SHMCBCache *cache, UCHAR *id, int idlen)
-{
- unsigned char tempasn[SSL_SESSION_MAX_DER];
- SSL_SESSION *pSession = NULL;
- SHMCBIndex *idx;
- SHMCBHeader *header;
- unsigned int curr_pos, loop, count;
- unsigned char *ptr;
- BOOL to_return = FALSE;
-
- ssl_log(s, SSL_LOG_TRACE, "entering shmcb_remove_session_id");
-
- /* If there's entries to expire, ditch them first thing. */
- /* shmcb_expire_division(s, queue, cache); */
-
- /* Regarding the above ... hmmm ... I know my expiry code is slightly
- * "faster" than all this remove stuff ... but if the higher level
- * code calls a "remove" operation (and this *only* seems to happen
- * when it has spotted an expired session before we had a chance to)
- * then it should get credit for a remove (stats-wise). Also, in the
- * off-chance that the server *requests* a renegotiate and wants to
- * wipe the session clean we should give that priority over our own
- * routine expiry handling. So I've moved the expiry check to *after*
- * this general remove stuff. */
- curr_pos = shmcb_get_safe_uint(queue->first_pos);
- count = shmcb_get_safe_uint(queue->pos_count);
- header = cache->header;
- for (loop = 0; loop < count; loop++) {
- ssl_log(s, SSL_LOG_TRACE, "loop=%u, count=%u, curr_pos=%u",
- loop, count, curr_pos);
- idx = shmcb_get_index(queue, curr_pos);
- ssl_log(s, SSL_LOG_TRACE, "idx->s_id2=%u, id[1]=%u", idx->s_id2,
- id[1]);
- /* Only look into the session further if the second byte of the
- * session_id matches. */
- if (idx->s_id2 == id[1]) {
- ssl_log(s, SSL_LOG_TRACE, "at index %u, found possible "
- "session match", curr_pos);
- shmcb_cyclic_cton_memcpy(header->cache_data_size,
- tempasn, cache->data,
- shmcb_get_safe_uint(&(idx->offset)),
- SSL_SESSION_MAX_DER);
- ptr = tempasn;
- pSession = d2i_SSL_SESSION(NULL, &ptr, SSL_SESSION_MAX_DER);
- if (pSession == NULL) {
- ssl_log(s, SSL_LOG_ERROR, "shmcb_remove_session_id, "
- "internal error");
- goto end;
- }
- if ((pSession->session_id_length == idlen)
- && (memcmp(id, pSession->session_id, idlen) == 0)) {
- ssl_log(s, SSL_LOG_TRACE, "a match!");
- /* Scrub out this session "quietly" */
- idx->removed = (unsigned char) 1;
- SSL_SESSION_free(pSession);
- to_return = TRUE;
- goto end;
- }
- ssl_log(s, SSL_LOG_TRACE, "not a match");
- SSL_SESSION_free(pSession);
- pSession = NULL;
- }
- curr_pos = shmcb_cyclic_increment(header->index_num, curr_pos, 1);
- }
- ssl_log(s, SSL_LOG_TRACE, "no matching sessions were found");
-
- /* If there's entries to expire, ditch them now. */
- shmcb_expire_division(s, queue, cache);
-end:
- ssl_log(s, SSL_LOG_TRACE, "leaving shmcb_remove_session_id");
- return to_return;
-}
-