From: Joe Orton Date: Tue, 25 Nov 2003 15:46:37 +0000 (+0000) Subject: Remove shmht session cache in favour of shmcb; shmht has had X-Git-Tag: pre_ajp_proxy~1001 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9ddbb80f5155b61d4c96f8826da157d4fad88900;p=apache Remove shmht session cache in favour of shmcb; shmht has had data corruption bugs since being apr_rmm'ified. * config.m4, mod_ssl.dsp: Don't build ssl_util_table and ssl_scache_shmht. * ssl_util_table.h, ssl_util_table.c, ssl_scache_shmht.c: Removed files. * mod_ssl.h (SSLModConfigRec): Use a void * pointer for storing the scache-specific data. * ssl_engine_config.c (ssl_cmd_SSLSessionCache): Treat shmht: as shmcb:. * ssl_scache.c: Remove shmht hooks throughout. * ssl_scache_shmcb.c: Remove casts to use the table_t * pointer as a void *. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@101888 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/CHANGES b/CHANGES index bb45b58f28..9fa02c9a7e 100644 --- a/CHANGES +++ b/CHANGES @@ -2,6 +2,9 @@ Changes with Apache 2.1.0-dev [Remove entries to the current 2.0 section below, when backported] + *) mod_ssl: Remove the shmht session cache, shmcb should be used + instead. [Joe Orton] + *) mod_ssl: SSL_VERSION_LIBRARY is set to the version string from the SSL library used at run-time, rather than at compile-time. PR: 23956 [Eric Seidel ] diff --git a/modules/ssl/config.m4 b/modules/ssl/config.m4 index a14254395a..956320204c 100644 --- a/modules/ssl/config.m4 +++ b/modules/ssl/config.m4 @@ -69,10 +69,8 @@ ssl_expr_scan.lo dnl ssl_scache.lo dnl ssl_scache_dbm.lo dnl ssl_scache_shmcb.lo dnl -ssl_scache_shmht.lo dnl ssl_util.lo dnl ssl_util_ssl.lo dnl -ssl_util_table.lo dnl " dnl # hook module into the Autoconf mechanism (--enable-ssl option) APACHE_MODULE(ssl, [SSL/TLS support (mod_ssl)], $ssl_objs, , no, [ diff --git a/modules/ssl/mod_ssl.dsp b/modules/ssl/mod_ssl.dsp index 9af7bbc9e5..4f8ed2c9d6 100644 --- a/modules/ssl/mod_ssl.dsp +++ b/modules/ssl/mod_ssl.dsp @@ -164,10 +164,6 @@ SOURCE=.\ssl_scache_shmcb.c # End Source File # Begin Source File -SOURCE=.\ssl_scache_shmht.c -# End Source File -# Begin Source File - SOURCE=.\ssl_util.c # End Source File # Begin Source File @@ -176,11 +172,6 @@ SOURCE=.\ssl_util_ssl.c # End Source File # Begin Source File -SOURCE=.\ssl_util_table.c -# End Source File -# End Group -# Begin Group "Header Files" - # PROP Default_Filter "*.h" # Begin Source File diff --git a/modules/ssl/mod_ssl.h b/modules/ssl/mod_ssl.h index ff9de413ca..8d8519072f 100644 --- a/modules/ssl/mod_ssl.h +++ b/modules/ssl/mod_ssl.h @@ -101,7 +101,6 @@ #include "ssl_toolkit_compat.h" #include "ssl_expr.h" #include "ssl_util_ssl.h" -#include "ssl_util_table.h" /* The #ifdef macros are only defined AFTER including the above * therefore we cannot include these system files at the top :-( @@ -307,7 +306,6 @@ typedef enum { SSL_SCMODE_UNSET = UNSET, SSL_SCMODE_NONE = 0, SSL_SCMODE_DBM = 1, - SSL_SCMODE_SHMHT = 2, SSL_SCMODE_SHMCB = 3 } ssl_scmode_t; @@ -391,7 +389,7 @@ typedef struct { int nSessionCacheDataSize; apr_shm_t *pSessionCacheDataMM; apr_rmm_t *pSessionCacheDataRMM; - apr_table_t *tSessionCacheDataTable; + void *tSessionCacheDataTable; ssl_mutexmode_t nMutexMode; apr_lockmech_e nMutexMech; const char *szMutexFile; diff --git a/modules/ssl/ssl_engine_config.c b/modules/ssl/ssl_engine_config.c index 6bb69e8576..2c5a9015f6 100644 --- a/modules/ssl/ssl_engine_config.c +++ b/modules/ssl/ssl_engine_config.c @@ -1006,48 +1006,8 @@ const char *ssl_cmd_SSLSessionCache(cmd_parms *cmd, arg+4); } } - else if ((arglen > 6) && strcEQn(arg, "shmht:", 6)) { -#if !APR_HAS_SHARED_MEMORY - return MODSSL_NO_SHARED_MEMORY_ERROR; -#endif - mc->nSessionCacheMode = SSL_SCMODE_SHMHT; - colon = ap_strchr_c(arg, ':'); - mc->szSessionCacheDataFile = - ap_server_root_relative(mc->pPool, colon+1); - if (!mc->szSessionCacheDataFile) { - return apr_psprintf(cmd->pool, - "SSLSessionCache: Invalid cache file path %s", - colon+1); - } - mc->tSessionCacheDataTable = NULL; - mc->nSessionCacheDataSize = 1024*512; /* 512KB */ - - if ((cp = strchr(mc->szSessionCacheDataFile, '('))) { - *cp++ = NUL; - - if (!(cp2 = strchr(cp, ')'))) { - return "SSLSessionCache: Invalid argument: " - "no closing parenthesis"; - } - - *cp2 = NUL; - - mc->nSessionCacheDataSize = atoi(cp); - - if (mc->nSessionCacheDataSize < 8192) { - return "SSLSessionCache: Invalid argument: " - "size has to be >= 8192 bytes"; - } - - if (mc->nSessionCacheDataSize >= APR_SHM_MAXSIZE) { - return apr_psprintf(cmd->pool, - "SSLSessionCache: Invalid argument: " - "size has to be < %d bytes on this " - "platform", APR_SHM_MAXSIZE); - } - } - } else if (((arglen > 4) && strcEQn(arg, "shm:", 4)) || + ((arglen > 6) && strcEQn(arg, "shmht:", 6)) || ((arglen > 6) && strcEQn(arg, "shmcb:", 6))) { #if !APR_HAS_SHARED_MEMORY return MODSSL_NO_SHARED_MEMORY_ERROR; diff --git a/modules/ssl/ssl_scache.c b/modules/ssl/ssl_scache.c index d9fc44b4bc..61c4a2cc9a 100644 --- a/modules/ssl/ssl_scache.c +++ b/modules/ssl/ssl_scache.c @@ -87,8 +87,7 @@ void ssl_scache_init(server_rec *s, apr_pool_t *p) if (mc->nSessionCacheMode == SSL_SCMODE_DBM) ssl_scache_dbm_init(s, p); - else if ((mc->nSessionCacheMode == SSL_SCMODE_SHMHT) || - (mc->nSessionCacheMode == SSL_SCMODE_SHMCB)) { + else if (mc->nSessionCacheMode == SSL_SCMODE_SHMCB) { void *data; const char *userdata_key = "ssl_scache_init"; @@ -98,10 +97,7 @@ void ssl_scache_init(server_rec *s, apr_pool_t *p) apr_pool_cleanup_null, s->process->pool); return; } - if (mc->nSessionCacheMode == SSL_SCMODE_SHMHT) - ssl_scache_shmht_init(s, p); - else if (mc->nSessionCacheMode == SSL_SCMODE_SHMCB) - ssl_scache_shmcb_init(s, p); + ssl_scache_shmcb_init(s, p); } } @@ -111,8 +107,6 @@ void ssl_scache_kill(server_rec *s) if (mc->nSessionCacheMode == SSL_SCMODE_DBM) ssl_scache_dbm_kill(s); - else if (mc->nSessionCacheMode == SSL_SCMODE_SHMHT) - ssl_scache_shmht_kill(s); else if (mc->nSessionCacheMode == SSL_SCMODE_SHMCB) ssl_scache_shmcb_kill(s); return; @@ -125,8 +119,6 @@ BOOL ssl_scache_store(server_rec *s, UCHAR *id, int idlen, time_t expiry, SSL_SE if (mc->nSessionCacheMode == SSL_SCMODE_DBM) rv = ssl_scache_dbm_store(s, id, idlen, expiry, sess); - else if (mc->nSessionCacheMode == SSL_SCMODE_SHMHT) - rv = ssl_scache_shmht_store(s, id, idlen, expiry, sess); else if (mc->nSessionCacheMode == SSL_SCMODE_SHMCB) rv = ssl_scache_shmcb_store(s, id, idlen, expiry, sess); return rv; @@ -139,8 +131,6 @@ SSL_SESSION *ssl_scache_retrieve(server_rec *s, UCHAR *id, int idlen) if (mc->nSessionCacheMode == SSL_SCMODE_DBM) sess = ssl_scache_dbm_retrieve(s, id, idlen); - else if (mc->nSessionCacheMode == SSL_SCMODE_SHMHT) - sess = ssl_scache_shmht_retrieve(s, id, idlen); else if (mc->nSessionCacheMode == SSL_SCMODE_SHMCB) sess = ssl_scache_shmcb_retrieve(s, id, idlen); return sess; @@ -152,8 +142,6 @@ void ssl_scache_remove(server_rec *s, UCHAR *id, int idlen) if (mc->nSessionCacheMode == SSL_SCMODE_DBM) ssl_scache_dbm_remove(s, id, idlen); - else if (mc->nSessionCacheMode == SSL_SCMODE_SHMHT) - ssl_scache_shmht_remove(s, id, idlen); else if (mc->nSessionCacheMode == SSL_SCMODE_SHMCB) ssl_scache_shmcb_remove(s, id, idlen); return; @@ -165,8 +153,6 @@ void ssl_scache_status(server_rec *s, apr_pool_t *p, void (*func)(char *, void * if (mc->nSessionCacheMode == SSL_SCMODE_DBM) ssl_scache_dbm_status(s, p, func, arg); - else if (mc->nSessionCacheMode == SSL_SCMODE_SHMHT) - ssl_scache_shmht_status(s, p, func, arg); else if (mc->nSessionCacheMode == SSL_SCMODE_SHMCB) ssl_scache_shmcb_status(s, p, func, arg); return; @@ -178,8 +164,6 @@ void ssl_scache_expire(server_rec *s) if (mc->nSessionCacheMode == SSL_SCMODE_DBM) ssl_scache_dbm_expire(s); - else if (mc->nSessionCacheMode == SSL_SCMODE_SHMHT) - ssl_scache_shmht_expire(s); else if (mc->nSessionCacheMode == SSL_SCMODE_SHMCB) ssl_scache_shmcb_expire(s); return; diff --git a/modules/ssl/ssl_scache_shmcb.c b/modules/ssl/ssl_scache_shmcb.c index b079325109..8d058fea64 100644 --- a/modules/ssl/ssl_scache_shmcb.c +++ b/modules/ssl/ssl_scache_shmcb.c @@ -399,11 +399,9 @@ void ssl_scache_shmcb_init(server_rec *s, apr_pool_t *p) "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. :-) + * Success ... */ - mc->tSessionCacheDataTable = (table_t *) shm_segment; + mc->tSessionCacheDataTable = shm_segment; return; } @@ -422,13 +420,11 @@ BOOL ssl_scache_shmcb_store(server_rec *s, UCHAR *id, int idlen, time_t timeout, SSL_SESSION * pSession) { SSLModConfigRec *mc = myModConfig(s); - 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)) + if (!shmcb_store_session(s, mc->tSessionCacheDataTable, id, idlen, + pSession, timeout)) /* in this cache engine, "stores" should never fail. */ ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "'shmcb' code was unable to store a " @@ -445,13 +441,10 @@ BOOL ssl_scache_shmcb_store(server_rec *s, UCHAR *id, int idlen, SSL_SESSION *ssl_scache_shmcb_retrieve(server_rec *s, UCHAR *id, int idlen) { SSLModConfigRec *mc = myModConfig(s); - 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); + pSession = shmcb_retrieve_session(s, mc->tSessionCacheDataTable, id, idlen); ssl_mutex_off(s); if (pSession) ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, @@ -469,12 +462,9 @@ SSL_SESSION *ssl_scache_shmcb_retrieve(server_rec *s, UCHAR *id, int idlen) void ssl_scache_shmcb_remove(server_rec *s, UCHAR *id, int idlen) { SSLModConfigRec *mc = myModConfig(s); - void *shm_segment; - /* We've kludged our pointer into the other cache's member variable. */ - shm_segment = (void *) mc->tSessionCacheDataTable; ssl_mutex_on(s); - shmcb_remove_session(s, shm_segment, id, idlen); + shmcb_remove_session(s, mc->tSessionCacheDataTable, id, idlen); ssl_mutex_off(s); } @@ -492,7 +482,6 @@ void ssl_scache_shmcb_status(server_rec *s, apr_pool_t *p, 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; @@ -501,11 +490,8 @@ void ssl_scache_shmcb_status(server_rec *s, apr_pool_t *p, ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "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); + shmcb_get_header(mc->tSessionCacheDataTable, &header); total = cache_total = non_empty_divisions = 0; average_expiry = max_expiry = min_expiry = 0; expiry_total = 0; diff --git a/modules/ssl/ssl_scache_shmht.c b/modules/ssl/ssl_scache_shmht.c deleted file mode 100644 index 74e36a85ef..0000000000 --- a/modules/ssl/ssl_scache_shmht.c +++ /dev/null @@ -1,384 +0,0 @@ -/* _ _ -** _ __ ___ ___ __| | ___ ___| | mod_ssl -** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL -** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org -** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org -** |_____| -** ssl_scache_shmht.c -** Session Cache via Shared Memory (Hash Table Variant) -*/ - -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2003 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 THE APACHE SOFTWARE FOUNDATION OR - * ITS 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" - -/* - * Wrapper functions for table library which resemble malloc(3) & Co - * but use the variants from the MM shared memory library. - */ - -static void *ssl_scache_shmht_malloc(void *opt_param, size_t size) -{ - SSLModConfigRec *mc = myModConfig((server_rec *)opt_param); - - apr_rmm_off_t off = apr_rmm_calloc(mc->pSessionCacheDataRMM, size); - return apr_rmm_addr_get(mc->pSessionCacheDataRMM, off); -} - -static void *ssl_scache_shmht_calloc(void *opt_param, - size_t number, size_t size) -{ - SSLModConfigRec *mc = myModConfig((server_rec *)opt_param); - - apr_rmm_off_t off = apr_rmm_calloc(mc->pSessionCacheDataRMM, (number*size)); - - return apr_rmm_addr_get(mc->pSessionCacheDataRMM, off); -} - -static void *ssl_scache_shmht_realloc(void *opt_param, void *ptr, size_t size) -{ - SSLModConfigRec *mc = myModConfig((server_rec *)opt_param); - - apr_rmm_off_t off = apr_rmm_realloc(mc->pSessionCacheDataRMM, ptr, size); - return apr_rmm_addr_get(mc->pSessionCacheDataRMM, off); -} - -static void ssl_scache_shmht_free(void *opt_param, void *ptr) -{ - SSLModConfigRec *mc = myModConfig((server_rec *)opt_param); - - apr_rmm_off_t off = apr_rmm_offset_get(mc->pSessionCacheDataRMM, ptr); - apr_rmm_free(mc->pSessionCacheDataRMM, off); - return; -} - -/* - * Now the actual session cache implementation - * based on a hash table inside a shared memory segment. - */ - -void ssl_scache_shmht_init(server_rec *s, apr_pool_t *p) -{ - SSLModConfigRec *mc = myModConfig(s); - table_t *ta; - int ta_errno; - apr_size_t avail; - int n; - apr_status_t rv; - - /* - * Create shared memory segment - */ - if (mc->szSessionCacheDataFile == NULL) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, - "SSLSessionCache required"); - ssl_die(); - } - - if ((rv = apr_shm_create(&(mc->pSessionCacheDataMM), - mc->nSessionCacheDataSize, - mc->szSessionCacheDataFile, mc->pPool)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, - "Cannot allocate shared memory"); - ssl_die(); - } - - if ((rv = apr_rmm_init(&(mc->pSessionCacheDataRMM), NULL, - apr_shm_baseaddr_get(mc->pSessionCacheDataMM), - mc->nSessionCacheDataSize, mc->pPool)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, - "Cannot initialize rmm"); - ssl_die(); - } - ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, - "initialize MM %pp RMM %pp", - mc->pSessionCacheDataMM, mc->pSessionCacheDataRMM); - - /* - * Create hash table in shared memory segment - */ - avail = mc->nSessionCacheDataSize; - n = (avail/2) / 1024; - n = n < 10 ? 10 : n; - - /* - * Passing server_rec as opt_param to table_alloc so that we can do - * logging if required ssl_util_table. Otherwise, mc is sufficient. - */ - if ((ta = table_alloc(n, &ta_errno, - ssl_scache_shmht_malloc, - ssl_scache_shmht_calloc, - ssl_scache_shmht_realloc, - ssl_scache_shmht_free, s )) == NULL) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, - "Cannot allocate hash table in shared memory: %s", - table_strerror(ta_errno)); - ssl_die(); - } - - table_attr(ta, TABLE_FLAG_AUTO_ADJUST|TABLE_FLAG_ADJUST_DOWN); - table_set_data_alignment(ta, sizeof(char *)); - table_clear(ta); - mc->tSessionCacheDataTable = ta; - - /* - * Log the done work - */ - ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, - "Init: Created hash-table (%d buckets) " - "in shared memory (%" APR_SIZE_T_FMT - " bytes) for SSL session cache", - n, avail); - return; -} - -void ssl_scache_shmht_kill(server_rec *s) -{ - SSLModConfigRec *mc = myModConfig(s); - - if (mc->pSessionCacheDataRMM != NULL) { - apr_rmm_destroy(mc->pSessionCacheDataRMM); - mc->pSessionCacheDataRMM = NULL; - } - - if (mc->pSessionCacheDataMM != NULL) { - apr_shm_destroy(mc->pSessionCacheDataMM); - mc->pSessionCacheDataMM = NULL; - } - return; -} - -BOOL ssl_scache_shmht_store(server_rec *s, UCHAR *id, int idlen, time_t expiry, SSL_SESSION *sess) -{ - SSLModConfigRec *mc = myModConfig(s); - void *vp; - UCHAR ucaData[SSL_SESSION_MAX_DER]; - int nData; - UCHAR *ucp; - - /* streamline session data */ - if ((nData = i2d_SSL_SESSION(sess, NULL)) > sizeof(ucaData)) - return FALSE; - ucp = ucaData; - i2d_SSL_SESSION(sess, &ucp); - - ssl_mutex_on(s); - if (table_insert_kd(mc->tSessionCacheDataTable, - id, idlen, NULL, sizeof(time_t)+nData, - NULL, &vp, 1) != TABLE_ERROR_NONE) { - ssl_mutex_off(s); - return FALSE; - } - memcpy(vp, &expiry, sizeof(time_t)); - memcpy((char *)vp+sizeof(time_t), ucaData, nData); - ssl_mutex_off(s); - - /* allow the regular expiring to occur */ - ssl_scache_shmht_expire(s); - - return TRUE; -} - -SSL_SESSION *ssl_scache_shmht_retrieve(server_rec *s, UCHAR *id, int idlen) -{ - SSLModConfigRec *mc = myModConfig(s); - void *vp; - SSL_SESSION *sess = NULL; - UCHAR *ucpData; - int nData; - time_t expiry; - time_t now; - int n; - - /* allow the regular expiring to occur */ - ssl_scache_shmht_expire(s); - - /* lookup key in table */ - ssl_mutex_on(s); - if (table_retrieve(mc->tSessionCacheDataTable, - id, idlen, &vp, &n) != TABLE_ERROR_NONE) { - ssl_mutex_off(s); - return NULL; - } - - /* copy over the information to the SCI */ - nData = n-sizeof(time_t); - ucpData = (UCHAR *)malloc(nData); - if (ucpData == NULL) { - ssl_mutex_off(s); - return NULL; - } - memcpy(&expiry, vp, sizeof(time_t)); - memcpy(ucpData, (char *)vp+sizeof(time_t), nData); - ssl_mutex_off(s); - - /* make sure the stuff is still not expired */ - now = time(NULL); - if (expiry <= now) { - ssl_scache_shmht_remove(s, id, idlen); - return NULL; - } - - /* unstreamed SSL_SESSION */ - sess = d2i_SSL_SESSION(NULL, &ucpData, nData); - - return sess; -} - -void ssl_scache_shmht_remove(server_rec *s, UCHAR *id, int idlen) -{ - SSLModConfigRec *mc = myModConfig(s); - - /* remove value under key in table */ - ssl_mutex_on(s); - table_delete(mc->tSessionCacheDataTable, id, idlen, NULL, NULL); - ssl_mutex_off(s); - return; -} - -void ssl_scache_shmht_expire(server_rec *s) -{ - SSLModConfigRec *mc = myModConfig(s); - SSLSrvConfigRec *sc = mySrvConfig(s); - static time_t tLast = 0; - table_linear_t iterator; - time_t tExpiresAt; - void *vpKey; - void *vpKeyThis; - void *vpData; - int nKey; - int nKeyThis; - int nData; - int nElements = 0; - int nDeleted = 0; - int bDelete; - int rc; - time_t tNow; - - /* - * make sure the expiration for still not-accessed session - * cache entries is done only from time to time - */ - tNow = time(NULL); - if (tNow < tLast+sc->session_cache_timeout) - return; - tLast = tNow; - - ssl_mutex_on(s); - if (table_first_r(mc->tSessionCacheDataTable, &iterator, - &vpKey, &nKey, &vpData, &nData) == TABLE_ERROR_NONE) { - do { - bDelete = FALSE; - nElements++; - if (nData < sizeof(time_t) || vpData == NULL) - bDelete = TRUE; - else { - memcpy(&tExpiresAt, vpData, sizeof(time_t)); - /* - * XXX : Force the record to be cleaned up. TBD (Madhu) - * tExpiresAt = tNow; - */ - if (tExpiresAt <= tNow) - bDelete = TRUE; - } - vpKeyThis = vpKey; - nKeyThis = nKey; - rc = table_next_r(mc->tSessionCacheDataTable, &iterator, - &vpKey, &nKey, &vpData, &nData); - if (bDelete) { - table_delete(mc->tSessionCacheDataTable, - vpKeyThis, nKeyThis, NULL, NULL); - nDeleted++; - } - } while (rc == TABLE_ERROR_NONE); - /* (vpKeyThis != vpKey) && (nKeyThis != nKey) */ - } - ssl_mutex_off(s); - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "Inter-Process Session Cache (SHMHT) Expiry: " - "old: %d, new: %d, removed: %d", - nElements, nElements-nDeleted, nDeleted); - return; -} - -void ssl_scache_shmht_status(server_rec *s, apr_pool_t *p, void (*func)(char *, void *), void *arg) -{ - SSLModConfigRec *mc = myModConfig(s); - void *vpKey; - void *vpData; - int nKey; - int nData; - int nElem; - int nSize; - int nAverage; - - nElem = 0; - nSize = 0; - ssl_mutex_on(s); - if (table_first(mc->tSessionCacheDataTable, - &vpKey, &nKey, &vpData, &nData) == TABLE_ERROR_NONE) { - do { - if (vpKey == NULL || vpData == NULL) - continue; - nElem += 1; - nSize += nData; - } while (table_next(mc->tSessionCacheDataTable, - &vpKey, &nKey, &vpData, &nData) == TABLE_ERROR_NONE); - } - ssl_mutex_off(s); - if (nSize > 0 && nElem > 0) - nAverage = nSize / nElem; - else - nAverage = 0; - func(apr_psprintf(p, "cache type: SHMHT, maximum size: %d bytes
", mc->nSessionCacheDataSize), arg); - func(apr_psprintf(p, "current sessions: %d, current size: %d bytes
", nElem, nSize), arg); - func(apr_psprintf(p, "average session size: %d bytes
", nAverage), arg); - return; -} diff --git a/modules/ssl/ssl_util_table.c b/modules/ssl/ssl_util_table.c deleted file mode 100644 index 6e6f1d5c75..0000000000 --- a/modules/ssl/ssl_util_table.c +++ /dev/null @@ -1,2551 +0,0 @@ -/* _ _ -** _ __ ___ ___ __| | ___ ___| | mod_ssl -** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL -** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org -** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org -** |_____| -** ssl_util_table.c -** High Performance Hash Table Functions -*/ - -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2003 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 THE APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - */ - -/* - * Generic hash table handler - * Table 4.1.0 July-28-1998 - * - * This library is a generic open hash table with buckets and - * linked lists. It is pretty high performance. Each element - * has a key and a data. The user indexes on the key to find the - * data. - * - * Copyright 1998 by Gray Watson - * - * Permission to use, copy, modify, and distribute this software for any - * purpose and without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies, - * and that the name of Gray Watson not be used in advertising or - * publicity pertaining to distribution of the document or software - * without specific, written prior permission. - * - * Gray Watson makes no representations about the suitability of the - * software described herein for any purpose. It is provided "as is" - * without express or implied warranty. - * - * Modified in March 1999 by Ralf S. Engelschall - * for use in the mod_ssl project: - * o merged table_loc.h header into table.c - * o removed fillproto-comments from table.h - * o removed mmap() support because it's too unportable - * o added support for MM library via ta_{malloc,calloc,realloc,free} - */ - -#include -#include - -/* forward definitions for table.h */ -typedef struct table_st table_t; -typedef struct table_entry_st table_entry_t; - -#define TABLE_PRIVATE -#include "ssl_util_table.h" -#include "mod_ssl.h" - -/****************************** local defines ******************************/ - -#ifndef BITSPERBYTE -#define BITSPERBYTE 8 -#endif -#ifndef BITS -#define BITS(type) (BITSPERBYTE * (int)sizeof(type)) -#endif - -#define TABLE_MAGIC 0xBADF00D /* very magic magicness */ -#define LINEAR_MAGIC 0xAD00D00 /* magic value for linear struct */ -#define DEFAULT_SIZE 1024 /* default table size */ -#define MAX_ALIGNMENT 128 /* max alignment value */ -#define MAX_SORT_SPLITS 128 /* qsort can handle 2^128 entries */ - -/* returns 1 when we should grow or shrink the table */ -#define SHOULD_TABLE_GROW(tab) ((tab)->ta_entry_n > (tab)->ta_bucket_n * 2) -#define SHOULD_TABLE_SHRINK(tab) ((tab)->ta_entry_n < (tab)->ta_bucket_n / 2) - -/* - * void HASH_MIX - * - * DESCRIPTION: - * - * Mix 3 32-bit values reversibly. For every delta with one or two bits - * set, and the deltas of all three high bits or all three low bits, - * whether the original value of a,b,c is almost all zero or is - * uniformly distributed. - * - * If HASH_MIX() is run forward or backward, at least 32 bits in a,b,c - * have at least 1/4 probability of changing. If mix() is run - * forward, every bit of c will change between 1/3 and 2/3 of the - * time. (Well, 22/100 and 78/100 for some 2-bit deltas.) - * - * HASH_MIX() takes 36 machine instructions, but only 18 cycles on a - * superscalar machine (like a Pentium or a Sparc). No faster mixer - * seems to work, that's the result of my brute-force search. There - * were about 2^68 hashes to choose from. I only tested about a - * billion of those. - */ -#define HASH_MIX(a, b, c) \ - do { \ - a -= b; a -= c; a ^= (c >> 13); \ - b -= c; b -= a; b ^= (a << 8); \ - c -= a; c -= b; c ^= (b >> 13); \ - a -= b; a -= c; a ^= (c >> 12); \ - b -= c; b -= a; b ^= (a << 16); \ - c -= a; c -= b; c ^= (b >> 5); \ - a -= b; a -= c; a ^= (c >> 3); \ - b -= c; b -= a; b ^= (a << 10); \ - c -= a; c -= b; c ^= (b >> 15); \ - } while(0) - -#define TABLE_POINTER(table, type, pnt) (pnt) - -/* - * Macros to get at the key and the data pointers - */ -#define ENTRY_KEY_BUF(entry_p) ((entry_p)->te_key_buf) -#define ENTRY_DATA_BUF(tab_p, entry_p) \ - (ENTRY_KEY_BUF(entry_p) + (entry_p)->te_key_size) - -/* - * Table structures... - */ - -/* - * HACK: this should be equiv as the table_entry_t without the key_buf - * char. We use this with the ENTRY_SIZE() macro above which solves - * the problem with the lack of the [0] GNU hack. We use the - * table_entry_t structure to better map the memory and make things - * faster. - */ -typedef struct table_shell_st { - unsigned int te_key_size; /* size of data */ - unsigned int te_data_size; /* size of data */ - struct table_shell_st *te_next_p; /* pointer to next in the list */ - /* NOTE: this does not have the te_key_buf field here */ -} table_shell_t; - -/* - * Elements in the bucket linked-lists. The key[1] is the start of - * the key with the rest of the key and all of the data information - * packed in memory directly after the end of this structure. - * - * NOTE: if this structure is changed, the table_shell_t must be changed - * to match. - */ -struct table_entry_st { - unsigned int te_key_size; /* size of data */ - unsigned int te_data_size; /* size of data */ - struct table_entry_st *te_next_p; /* pointer to next in the list */ - unsigned char te_key_buf[1]; /* 1st byte of key buf */ -}; - -/* external structure for debuggers be able to see void */ -typedef table_entry_t table_entry_ext_t; - -/* main table structure */ -struct table_st { - unsigned int ta_magic; /* magic number */ - unsigned int ta_flags; /* table's flags defined in table.h */ - unsigned int ta_bucket_n; /* num of buckets, should be 2^X */ - unsigned int ta_entry_n; /* num of entries in all buckets */ - unsigned int ta_data_align; /* data alignment value */ - table_entry_t **ta_buckets; /* array of linked lists */ - table_linear_t ta_linear; /* linear tracking */ - unsigned long ta_file_size; /* size of on-disk space */ - void *(*ta_malloc)(void *opt_param, size_t size); - void *(*ta_calloc)(void *opt_param, size_t number, size_t size); - void *(*ta_realloc)(void *opt_param, void *ptr, size_t size); - void (*ta_free)(void *opt_param, void *ptr); - void *opt_param; -}; - -/* external table structure for debuggers */ -typedef table_t table_ext_t; - -/* local comparison functions */ -typedef int (*compare_t) (const void *element1_p, const void *element2_p, - table_compare_t user_compare, - const table_t * table_p); - -/* - * to map error to string - */ -typedef struct { - int es_error; /* error number */ - char *es_string; /* assocaited string */ -} error_str_t; - -static error_str_t errors[] = -{ - {TABLE_ERROR_NONE, "no error"}, - {TABLE_ERROR_PNT, "invalid table pointer"}, - {TABLE_ERROR_ARG_NULL, "buffer argument is null"}, - {TABLE_ERROR_SIZE, "incorrect size argument"}, - {TABLE_ERROR_OVERWRITE, "key exists and no overwrite"}, - {TABLE_ERROR_NOT_FOUND, "key does not exist"}, - {TABLE_ERROR_ALLOC, "error allocating memory"}, - {TABLE_ERROR_LINEAR, "linear access not in progress"}, - {TABLE_ERROR_OPEN, "could not open file"}, - {TABLE_ERROR_SEEK, "could not seek to position in file"}, - {TABLE_ERROR_READ, "could not read from file"}, - {TABLE_ERROR_WRITE, "could not write to file"}, - {TABLE_ERROR_EMPTY, "table is empty"}, - {TABLE_ERROR_NOT_EMPTY, "table contains data"}, - {TABLE_ERROR_ALIGNMENT, "invalid alignment value"}, - {0} -}; - -#define INVALID_ERROR "invalid error code" - - -/********************** wrappers for system functions ************************/ -static void *sys_malloc(void *param, size_t size) -{ - return malloc(size); -} - -static void *sys_calloc(void *param, size_t size1, size_t size2) -{ - return calloc(size1, size2); -} - -static void *sys_realloc(void *param, void *ptr, size_t size) -{ - return realloc(ptr, size); -} - -static void sys_free(void *param, void *ptr) -{ - free(ptr); -} - -/****************************** local functions ******************************/ - -/* - * static table_entry_t *first_entry - * - * DESCRIPTION: - * - * Return the first entry in the table. It will set the linear - * structure counter to the position of the first entry. - * - * RETURNS: - * - * Success: A pointer to the first entry in the table. - * - * Failure: NULL if there is no first entry. - * - * ARGUMENTS: - * - * table_p - Table whose next entry we are finding. - * - * linear_p - Pointer to a linear structure which we will advance and - * then find the corresponding entry. - */ -static table_entry_t *first_entry(table_t * table_p, - table_linear_t * linear_p) -{ - table_entry_t *entry_p; - unsigned int bucket_c = 0; - - /* look for the first non-empty bucket */ - for (bucket_c = 0; bucket_c < table_p->ta_bucket_n; bucket_c++) { - entry_p = table_p->ta_buckets[bucket_c]; - if (entry_p != NULL) { - if (linear_p != NULL) { - linear_p->tl_bucket_c = bucket_c; - linear_p->tl_entry_c = 0; - } - return TABLE_POINTER(table_p, table_entry_t *, entry_p); - } - } - - return NULL; -} - -/* - * static table_entry_t *next_entry - * - * DESCRIPTION: - * - * Return the next entry in the table which is past the position in - * our linear pointer. It will advance the linear structure counters. - * - * RETURNS: - * - * Success: A pointer to the next entry in the table. - * - * Failure: NULL. - * - * ARGUMENTS: - * - * table_p - Table whose next entry we are finding. - * - * linear_p - Pointer to a linear structure which we will advance and - * then find the corresponding entry. - * - * error_p - Pointer to an integer which when the routine returns will - * contain a table error code. - */ -static table_entry_t *next_entry(table_t * table_p, table_linear_t * linear_p, - int *error_p) -{ - table_entry_t *entry_p; - int entry_c; - - /* can't next if we haven't first-ed */ - if (linear_p == NULL) { - if (error_p != NULL) - *error_p = TABLE_ERROR_LINEAR; - return NULL; - } - - if (linear_p->tl_bucket_c >= table_p->ta_bucket_n) { - /* - * NOTE: this might happen if we delete an item which shortens the - * table bucket numbers. - */ - if (error_p != NULL) - *error_p = TABLE_ERROR_NOT_FOUND; - return NULL; - } - - linear_p->tl_entry_c++; - - /* find the entry which is the nth in the list */ - entry_p = table_p->ta_buckets[linear_p->tl_bucket_c]; - /* NOTE: we swap the order here to be more efficient */ - for (entry_c = linear_p->tl_entry_c; entry_c > 0; entry_c--) { - /* did we reach the end of the list? */ - if (entry_p == NULL) - break; - entry_p = TABLE_POINTER(table_p, table_entry_t *, entry_p)->te_next_p; - } - - /* did we find an entry in the current bucket? */ - if (entry_p != NULL) { - if (error_p != NULL) - *error_p = TABLE_ERROR_NONE; - return TABLE_POINTER(table_p, table_entry_t *, entry_p); - } - - /* find the first entry in the next non-empty bucket */ - - linear_p->tl_entry_c = 0; - for (linear_p->tl_bucket_c++; linear_p->tl_bucket_c < table_p->ta_bucket_n; - linear_p->tl_bucket_c++) { - entry_p = table_p->ta_buckets[linear_p->tl_bucket_c]; - if (entry_p != NULL) { - if (error_p != NULL) - *error_p = TABLE_ERROR_NONE; - return TABLE_POINTER(table_p, table_entry_t *, entry_p); - } - } - - if (error_p != NULL) - *error_p = TABLE_ERROR_NOT_FOUND; - return NULL; -} - -/* - * static unsigned int hash - * - * DESCRIPTION: - * - * Hash a variable-length key into a 32-bit value. Every bit of the - * key affects every bit of the return value. Every 1-bit and 2-bit - * delta achieves avalanche. About (6 * len + 35) instructions. The - * best hash table sizes are powers of 2. There is no need to use mod - * (sooo slow!). If you need less than 32 bits, use a bitmask. For - * example, if you need only 10 bits, do h = (h & hashmask(10)); In - * which case, the hash table should have hashsize(10) elements. - * - * By Bob Jenkins, 1996. bob_jenkins@compuserve.com. You may use - * this code any way you wish, private, educational, or commercial. - * It's free. See - * http://ourworld.compuserve.com/homepages/bob_jenkins/evahash.htm - * Use for hash table lookup, or anything where one collision in 2^^32 - * is acceptable. Do NOT use for cryptographic purposes. - * - * RETURNS: - * - * Returns a 32-bit hash value. - * - * ARGUMENTS: - * - * key - Key (the unaligned variable-length array of bytes) that we - * are hashing. - * - * length - Length of the key in bytes. - * - * init_val - Initialization value of the hash if you need to hash a - * number of strings together. For instance, if you are hashing N - * strings (unsigned char **)keys, do it like this: - * - * for (i=0, h=0; i= 12; len -= 12) { - a += (key_p[0] - + ((unsigned long) key_p[1] << 8) - + ((unsigned long) key_p[2] << 16) - + ((unsigned long) key_p[3] << 24)); - b += (key_p[4] - + ((unsigned long) key_p[5] << 8) - + ((unsigned long) key_p[6] << 16) - + ((unsigned long) key_p[7] << 24)); - c += (key_p[8] - + ((unsigned long) key_p[9] << 8) - + ((unsigned long) key_p[10] << 16) - + ((unsigned long) key_p[11] << 24)); - HASH_MIX(a, b, c); - key_p += 12; - } - - c += length; - - /* all the case statements fall through to the next */ - switch (len) { - case 11: - c += ((unsigned long) key_p[10] << 24); - case 10: - c += ((unsigned long) key_p[9] << 16); - case 9: - c += ((unsigned long) key_p[8] << 8); - /* the first byte of c is reserved for the length */ - case 8: - b += ((unsigned long) key_p[7] << 24); - case 7: - b += ((unsigned long) key_p[6] << 16); - case 6: - b += ((unsigned long) key_p[5] << 8); - case 5: - b += key_p[4]; - case 4: - a += ((unsigned long) key_p[3] << 24); - case 3: - a += ((unsigned long) key_p[2] << 16); - case 2: - a += ((unsigned long) key_p[1] << 8); - case 1: - a += key_p[0]; - /* case 0: nothing left to add */ - } - HASH_MIX(a, b, c); - - return c; -} - -/* - * static int entry_size - * - * DESCRIPTION: - * - * Calculates the appropriate size of an entry to include the key and - * data sizes as well as any associated alignment to the data. - * - * RETURNS: - * - * The associated size of the entry. - * - * ARGUMENTS: - * - * table_p - Table associated with the entries whose size we are - * determining. - * - * key_size - Size of the entry key. - * - * data - Size of the entry data. - */ -static int entry_size(const table_t * table_p, const unsigned int key_size, - const unsigned int data_size) -{ - int size, left; - - /* initial size -- key is already aligned if right after struct */ - size = sizeof(struct table_shell_st) + key_size; - - /* if there is no alignment then it is easy */ - if (table_p->ta_data_align == 0) - return size + data_size; - /* add in our alignement */ - left = size & (table_p->ta_data_align - 1); - if (left > 0) - size += table_p->ta_data_align - left; - /* we add the data size here after the alignment */ - size += data_size; - - return size; -} - -/* - * static unsigned char *entry_data_buf - * - * DESCRIPTION: - * - * Companion to the ENTRY_DATA_BUF macro but this handles any - * associated alignment to the data in the entry. - * - * RETURNS: - * - * Pointer to the data segment of the entry. - * - * ARGUMENTS: - * - * table_p - Table associated with the entry. - * - * entry_p - Entry whose data pointer we are determining. - */ -static unsigned char *entry_data_buf(const table_t * table_p, - const table_entry_t * entry_p) -{ - const unsigned char *buf_p; - int size, pad; - - buf_p = entry_p->te_key_buf + entry_p->te_key_size; - - /* if there is no alignment then it is easy */ - if (table_p->ta_data_align == 0) - return (unsigned char *) buf_p; - /* we need the size of the space before the data */ - size = sizeof(struct table_shell_st) + entry_p->te_key_size; - - /* add in our alignment */ - pad = size & (table_p->ta_data_align - 1); - if (pad > 0) - pad = table_p->ta_data_align - pad; - return (unsigned char *) buf_p + pad; -} - -/******************************* sort routines *******************************/ - -/* - * static int our_compare - * - * DESCRIPTION: - * - * Compare two entries by calling user's compare program or by using - * memcmp. - * - * RETURNS: - * - * < 0, == 0, or > 0 depending on whether p1 is > p2, == p2, < p2. - * - * ARGUMENTS: - * - * p1 - First entry pointer to compare. - * - * p2 - Second entry pointer to compare. - * - * compare - User comparison function. Ignored. - * - * table_p - Associated table being ordered. Ignored. - */ -static int local_compare(const void *p1, const void *p2, - table_compare_t compare, const table_t * table_p) -{ - const table_entry_t *const *ent1_p = p1, *const *ent2_p = p2; - int cmp; - unsigned int size; - - /* compare as many bytes as we can */ - size = (*ent1_p)->te_key_size; - if ((*ent2_p)->te_key_size < size) - size = (*ent2_p)->te_key_size; - cmp = memcmp(ENTRY_KEY_BUF(*ent1_p), ENTRY_KEY_BUF(*ent2_p), size); - /* if common-size equal, then if next more bytes, it is larger */ - if (cmp == 0) - cmp = (*ent1_p)->te_key_size - (*ent2_p)->te_key_size; - return cmp; -} - -/* - * static int external_compare - * - * DESCRIPTION: - * - * Compare two entries by calling user's compare program or by using - * memcmp. - * - * RETURNS: - * - * < 0, == 0, or > 0 depending on whether p1 is > p2, == p2, < p2. - * - * ARGUMENTS: - * - * p1 - First entry pointer to compare. - * - * p2 - Second entry pointer to compare. - * - * user_compare - User comparison function. - * - * table_p - Associated table being ordered. - */ -static int external_compare(const void *p1, const void *p2, - table_compare_t user_compare, - const table_t * table_p) -{ - const table_entry_t *const *ent1_p = p1, *const *ent2_p = p2; - /* since we know we are not aligned we can use the EXTRY_DATA_BUF macro */ - return user_compare(ENTRY_KEY_BUF(*ent1_p), (*ent1_p)->te_key_size, - ENTRY_DATA_BUF(table_p, *ent1_p), - (*ent1_p)->te_data_size, - ENTRY_KEY_BUF(*ent2_p), (*ent2_p)->te_key_size, - ENTRY_DATA_BUF(table_p, *ent2_p), - (*ent2_p)->te_data_size); -} - -/* - * static int external_compare_align - * - * DESCRIPTION: - * - * Compare two entries by calling user's compare program or by using - * memcmp. Alignment information is necessary. - * - * RETURNS: - * - * < 0, == 0, or > 0 depending on whether p1 is > p2, == p2, < p2. - * - * ARGUMENTS: - * - * p1 - First entry pointer to compare. - * - * p2 - Second entry pointer to compare. - * - * user_compare - User comparison function. - * - * table_p - Associated table being ordered. - */ -static int external_compare_align(const void *p1, const void *p2, - table_compare_t user_compare, - const table_t * table_p) -{ - const table_entry_t *const *ent1_p = p1, *const *ent2_p = p2; - /* since we are aligned we have to use the entry_data_buf function */ - return user_compare(ENTRY_KEY_BUF(*ent1_p), (*ent1_p)->te_key_size, - entry_data_buf(table_p, *ent1_p), - (*ent1_p)->te_data_size, - ENTRY_KEY_BUF(*ent2_p), (*ent2_p)->te_key_size, - entry_data_buf(table_p, *ent2_p), - (*ent2_p)->te_data_size); -} - -/* - * static void split - * - * DESCRIPTION: - * - * This sorts an array of longs via the quick sort algorithm (it's - * pretty quick) - * - * RETURNS: - * - * None. - * - * ARGUMENTS: - * - * first_p - Start of the list that we are splitting. - * - * last_p - Last entry in the list that we are splitting. - * - * compare - Comparison function which is handling the actual - * elements. This is either a local function or a function to setup - * the problem element key and data pointers which then hands off to - * the user function. - * - * user_compare - User comparison function. Could be NULL if we are - * just using a local comparison function. - * - * table_p - Associated table being sorted. - */ -static void split(void *first_p, void *last_p, compare_t compare, - table_compare_t user_compare, table_t * table_p) -{ - void *pivot_p, *left_p, *right_p, *left_last_p, *right_first_p; - void *firsts[MAX_SORT_SPLITS], *lasts[MAX_SORT_SPLITS]; - int split_c = 0; - - for (;;) { - - /* no need to split the list if it is < 2 elements */ - while (first_p >= last_p) { - if (split_c == 0) { - /* we are done */ - return; - } - split_c--; - first_p = firsts[split_c]; - last_p = lasts[split_c]; - } - - left_p = first_p; - right_p = last_p; - pivot_p = first_p; - - do { - /* scan from right hand side */ - while (right_p > left_p - && compare(right_p, pivot_p, user_compare, table_p) > 0) - right_p = (char *) right_p - sizeof(table_entry_t *); - /* scan from left hand side */ - while (right_p > left_p - && compare(pivot_p, left_p, user_compare, table_p) >= 0) - left_p = (char *) left_p + sizeof(table_entry_t *); - /* if the pointers haven't met then swap values */ - if (right_p > left_p) { - /* swap_bytes(left_p, right_p) */ - table_entry_t *temp; - - temp = *(table_entry_t **) left_p; - *(table_entry_t **) left_p = *(table_entry_t **) right_p; - *(table_entry_t **) right_p = temp; - } - } while (right_p > left_p); - - /* now we swap the pivot with the right-hand side */ - { - /* swap_bytes(pivot_p, right_p); */ - table_entry_t *temp; - - temp = *(table_entry_t **) pivot_p; - *(table_entry_t **) pivot_p = *(table_entry_t **) right_p; - *(table_entry_t **) right_p = temp; - } - pivot_p = right_p; - - /* save the section to the right of the pivot in our stack */ - right_first_p = (char *) pivot_p + sizeof(table_entry_t *); - left_last_p = (char *) pivot_p - sizeof(table_entry_t *); - - /* do we need to save the righthand side? */ - if (right_first_p < last_p) { - if (split_c >= MAX_SORT_SPLITS) { - /* sanity check here -- we should never get here */ - abort(); - } - firsts[split_c] = right_first_p; - lasts[split_c] = last_p; - split_c++; - } - - /* do the left hand side of the pivot */ - /* first_p = first_p */ - last_p = left_last_p; - } -} - -/*************************** exported routines *******************************/ - -/* - * table_t *table_alloc - * - * DESCRIPTION: - * - * Allocate a new table structure. - * - * RETURNS: - * - * A pointer to the new table structure which must be passed to - * table_free to be deallocated. On error a NULL is returned. - * - * ARGUMENTS: - * - * bucket_n - Number of buckets for the hash table. Our current hash - * value works best with base two numbers. Set to 0 to take the - * library default of 1024. - * - * error_p - Pointer to an integer which, if not NULL, will contain a - * table error code. - * - * malloc_f, realloc_f, free_f - Pointers to malloc(3)-, realloc(3)- - * and free(3)-style functions. - */ -table_t *table_alloc(const unsigned int bucket_n, int *error_p, - void *(*malloc_f)(void *opt_param, size_t size), - void *(*calloc_f)(void *opt_param, size_t number, size_t size), - void *(*realloc_f)(void *opt_param, void *ptr, size_t size), - void (*free_f)(void *opt_param, void *ptr), void *opt_param) -{ - table_t *table_p = NULL; - unsigned int buck_n; - - /* allocate a table structure */ - if (malloc_f != NULL) - table_p = malloc_f(opt_param, sizeof(table_t)); - else - table_p = malloc(sizeof(table_t)); - if (table_p == NULL) { - if (error_p != NULL) - *error_p = TABLE_ERROR_ALLOC; - return NULL; - } - - if (bucket_n > 0) - buck_n = bucket_n; - else - buck_n = DEFAULT_SIZE; - /* allocate the buckets which are NULLed */ - if (calloc_f != NULL) - table_p->ta_buckets = (table_entry_t **)calloc_f(opt_param, buck_n, - sizeof(table_entry_t *)); - else - table_p->ta_buckets = (table_entry_t **)calloc(buck_n, sizeof(table_entry_t *)); - if (table_p->ta_buckets == NULL) { - if (error_p != NULL) - *error_p = TABLE_ERROR_ALLOC; - if (free_f != NULL) - free_f(opt_param, table_p); - else - free(table_p); - return NULL; - } - - /* initialize structure */ - table_p->ta_magic = TABLE_MAGIC; - table_p->ta_flags = 0; - table_p->ta_bucket_n = buck_n; - table_p->ta_entry_n = 0; - table_p->ta_data_align = 0; - table_p->ta_linear.tl_magic = 0; - table_p->ta_linear.tl_bucket_c = 0; - table_p->ta_linear.tl_entry_c = 0; - table_p->ta_file_size = 0; - table_p->ta_malloc = malloc_f != NULL ? malloc_f : sys_malloc; - table_p->ta_calloc = calloc_f != NULL ? calloc_f : sys_calloc; - table_p->ta_realloc = realloc_f != NULL ? realloc_f : sys_realloc; - table_p->ta_free = free_f != NULL ? free_f : sys_free; - table_p->opt_param = opt_param; - - if (error_p != NULL) - *error_p = TABLE_ERROR_NONE; - return table_p; -} - -/* - * int table_attr - * - * DESCRIPTION: - * - * Set the attributes for the table. The available attributes are - * specified at the top of table.h. - * - * RETURNS: - * - * Success - TABLE_ERROR_NONE - * - * Failure - Table error code. - * - * ARGUMENTS: - * - * table_p - Pointer to a table structure which we will be altering. - * - * attr - Attribute(s) that we will be applying to the table. - */ -int table_attr(table_t * table_p, const int attr) -{ - if (table_p == NULL) - return TABLE_ERROR_ARG_NULL; - if (table_p->ta_magic != TABLE_MAGIC) - return TABLE_ERROR_PNT; - table_p->ta_flags = attr; - - return TABLE_ERROR_NONE; -} - -/* - * int table_set_data_alignment - * - * DESCRIPTION: - * - * Set the alignment for the data in the table. For data elements - * sizeof(long) is recommended unless you use smaller data types - * exclusively. - * - * WARNING: This must be done before any data gets put into the table. - * - * RETURNS: - * - * Success - TABLE_ERROR_NONE - * - * Failure - Table error code. - * - * ARGUMENTS: - * - * table_p - Pointer to a table structure which we will be altering. - * - * alignment - Alignment requested for the data. Must be a power of - * 2. Set to 0 for none. - */ -int table_set_data_alignment(table_t * table_p, const int alignment) -{ - int val; - - if (table_p == NULL) - return TABLE_ERROR_ARG_NULL; - if (table_p->ta_magic != TABLE_MAGIC) - return TABLE_ERROR_PNT; - if (table_p->ta_entry_n > 0) - return TABLE_ERROR_NOT_EMPTY; - /* defaults */ - if (alignment < 2) - table_p->ta_data_align = 0; - else { - /* verify we have a base 2 number */ - for (val = 2; val < MAX_ALIGNMENT; val *= 2) { - if (val == alignment) - break; - } - if (val >= MAX_ALIGNMENT) - return TABLE_ERROR_ALIGNMENT; - table_p->ta_data_align = alignment; - } - - return TABLE_ERROR_NONE; -} - -/* - * int table_clear - * - * DESCRIPTION: - * - * Clear out and free all elements in a table structure. - * - * RETURNS: - * - * Success - TABLE_ERROR_NONE - * - * Failure - Table error code. - * - * ARGUMENTS: - * - * table_p - Table structure pointer that we will be clearing. - */ -int table_clear(table_t * table_p) -{ - table_entry_t *entry_p, *next_p; - table_entry_t **bucket_p, **bounds_p; - - if (table_p == NULL) - return TABLE_ERROR_ARG_NULL; - if (table_p->ta_magic != TABLE_MAGIC) - return TABLE_ERROR_PNT; - /* free the table allocation and table structure */ - bounds_p = table_p->ta_buckets + table_p->ta_bucket_n; - for (bucket_p = table_p->ta_buckets; bucket_p < bounds_p; bucket_p++) { - for (entry_p = *bucket_p; entry_p != NULL; entry_p = next_p) { - /* record the next pointer before we free */ - next_p = entry_p->te_next_p; - table_p->ta_free(table_p->opt_param, entry_p); - } - /* clear the bucket entry after we free its entries */ - *bucket_p = NULL; - } - - /* reset table state info */ - table_p->ta_entry_n = 0; - table_p->ta_linear.tl_magic = 0; - table_p->ta_linear.tl_bucket_c = 0; - table_p->ta_linear.tl_entry_c = 0; - - return TABLE_ERROR_NONE; -} - -/* - * int table_free - * - * DESCRIPTION: - * - * Deallocates a table structure. - * - * RETURNS: - * - * Success - TABLE_ERROR_NONE - * - * Failure - Table error code. - * - * ARGUMENTS: - * - * table_p - Table structure pointer that we will be freeing. - */ -int table_free(table_t * table_p) -{ - int ret; - - if (table_p == NULL) - return TABLE_ERROR_ARG_NULL; - if (table_p->ta_magic != TABLE_MAGIC) - return TABLE_ERROR_PNT; - ret = table_clear(table_p); - - if (table_p->ta_buckets != NULL) - table_p->ta_free(table_p->opt_param, table_p->ta_buckets); - table_p->ta_magic = 0; - table_p->ta_free(table_p->opt_param, table_p); - - return ret; -} - -/* - * int table_insert_kd - * - * DESCRIPTION: - * - * Like table_insert except it passes back a pointer to the key and - * the data buffers after they have been inserted into the table - * structure. - * - * This routine adds a key/data pair both of which are made up of a - * buffer of bytes and an associated size. Both the key and the data - * will be copied into buffers allocated inside the table. If the key - * exists already, the associated data will be replaced if the - * overwrite flag is set, otherwise an error is returned. - * - * NOTE: be very careful changing the values since the table library - * provides the pointers to its memory. The key can _never_ be - * changed otherwise you will not find it again. The data can be - * changed but its length can never be altered unless you delete and - * re-insert it into the table. - * - * WARNING: The pointers to the key and data are not in any specific - * alignment. Accessing the key and/or data as an short, integer, or - * long pointer directly can cause problems. - * - * WARNING: Replacing a data cell (not inserting) will cause the table - * linked list to be temporarily invalid. Care must be taken with - * multiple threaded programs which are relying on the first/next - * linked list to be always valid. - * - * RETURNS: - * - * Success - TABLE_ERROR_NONE - * - * Failure - Table error code. - * - * ARGUMENTS: - * - * table_p - Table structure pointer into which we will be inserting a - * new key/data pair. - * - * key_buf - Buffer of bytes of the key that we are inserting. If you - * are storing an (int) as the key (for example) then key_buf should - * be a (int *). - * - * key_size - Size of the key_buf buffer. If set to < 0 then the - * library will do a strlen of key_buf and add 1 for the '\0'. If you - * are storing an (int) as the key (for example) then key_size should - * be sizeof(int). - * - * data_buf - Buffer of bytes of the data that we are inserting. If - * it is NULL then the library will allocate space for the data in the - * table without copying in any information. If data_buf is NULL and - * data_size is 0 then the library will associate a NULL data pointer - * with the key. If you are storing a (long) as the data (for - * example) then data_buf should be a (long *). - * - * data_size - Size of the data_buf buffer. If set to < 0 then the - * library will do a strlen of data_buf and add 1 for the '\0'. If - * you are storing an (long) as the key (for example) then key_size - * should be sizeof(long). - * - * key_buf_p - Pointer which, if not NULL, will be set to the address - * of the key storage that was allocated in the table. If you are - * storing an (int) as the key (for example) then key_buf_p should be - * (int **) i.e. the address of a (int *). - * - * data_buf_p - Pointer which, if not NULL, will be set to the address - * of the data storage that was allocated in the table. If you are - * storing an (long) as the data (for example) then data_buf_p should - * be (long **) i.e. the address of a (long *). - * - * overwrite - Flag which, if set to 1, will allow the overwriting of - * the data in the table with the new data if the key already exists - * in the table. - */ -int table_insert_kd(table_t * table_p, - const void *key_buf, const int key_size, - const void *data_buf, const int data_size, - void **key_buf_p, void **data_buf_p, - const char overwrite_b) -{ - int bucket; - unsigned int ksize, dsize; - table_entry_t *entry_p, *last_p; - void *key_copy_p, *data_copy_p; - - /* check the arguments */ - if (table_p == NULL) - return TABLE_ERROR_ARG_NULL; - if (table_p->ta_magic != TABLE_MAGIC) - return TABLE_ERROR_PNT; - if (key_buf == NULL) - return TABLE_ERROR_ARG_NULL; - /* data_buf can be null but size must be >= 0, if it isn't null size != 0 */ - if ((data_buf == NULL && data_size < 0) - || (data_buf != NULL && data_size == 0)) - return TABLE_ERROR_SIZE; - /* determine sizes of key and data */ - if (key_size < 0) - ksize = strlen((char *) key_buf) + sizeof(char); - else - ksize = key_size; - if (data_size < 0) - dsize = strlen((char *) data_buf) + sizeof(char); - else - dsize = data_size; - /* get the bucket number via a hash function */ - bucket = hash(key_buf, ksize, 0) % table_p->ta_bucket_n; - - /* look for the entry in this bucket, only check keys of the same size */ - last_p = NULL; - for (entry_p = table_p->ta_buckets[bucket]; - (entry_p != NULL) && (entry_p->te_next_p != last_p); - last_p = entry_p, entry_p = entry_p->te_next_p) { - if (entry_p->te_key_size == ksize - && memcmp(ENTRY_KEY_BUF(entry_p), key_buf, ksize) == 0) - break; - } - - /* did we find it? then we are in replace mode. */ - if (entry_p != NULL) { - - /* can we not overwrite existing data? */ - if (!overwrite_b) { - if (key_buf_p != NULL) - *key_buf_p = ENTRY_KEY_BUF(entry_p); - if (data_buf_p != NULL) { - if (entry_p->te_data_size == 0) - *data_buf_p = NULL; - else { - if (table_p->ta_data_align == 0) - *data_buf_p = ENTRY_DATA_BUF(table_p, entry_p); - else - *data_buf_p = entry_data_buf(table_p, entry_p); - } - } - return TABLE_ERROR_OVERWRITE; - } - - /* re-alloc entry's data if the new size != the old */ - if (dsize != entry_p->te_data_size) { - - /* - * First we delete it from the list to keep the list whole. - * This properly preserves the linked list in case we have a - * thread marching through the linked list while we are - * inserting. Maybe this is an unnecessary protection but it - * should not harm that much. - */ - if (last_p == NULL) - table_p->ta_buckets[bucket] = entry_p->te_next_p; - else - last_p->te_next_p = entry_p->te_next_p; - /* - * Realloc the structure which may change its pointer. NOTE: - * this may change any previous data_key_p and data_copy_p - * pointers. - */ - entry_p = (table_entry_t *) - table_p->ta_realloc(table_p->opt_param, entry_p, - entry_size(table_p, entry_p->te_key_size, dsize)); - if (entry_p == NULL) - return TABLE_ERROR_ALLOC; - /* add it back to the front of the list */ - entry_p->te_data_size = dsize; - entry_p->te_next_p = table_p->ta_buckets[bucket]; - table_p->ta_buckets[bucket] = entry_p; - } - - /* copy or replace data in storage */ - if (dsize > 0) { - if (table_p->ta_data_align == 0) - data_copy_p = ENTRY_DATA_BUF(table_p, entry_p); - else - data_copy_p = entry_data_buf(table_p, entry_p); - if (data_buf != NULL) - memcpy(data_copy_p, data_buf, dsize); - } - else - data_copy_p = NULL; - if (key_buf_p != NULL) - *key_buf_p = ENTRY_KEY_BUF(entry_p); - if (data_buf_p != NULL) - *data_buf_p = data_copy_p; - /* returning from the section where we were overwriting table data */ - return TABLE_ERROR_NONE; - } - - /* - * It is a new entry. - */ - - /* allocate a new entry */ - entry_p = (table_entry_t *) - table_p->ta_malloc(table_p->opt_param, - entry_size(table_p, ksize, dsize)); - if (entry_p == NULL) - return TABLE_ERROR_ALLOC; - /* copy key into storage */ - entry_p->te_key_size = ksize; - key_copy_p = ENTRY_KEY_BUF(entry_p); - memcpy(key_copy_p, key_buf, ksize); - - /* copy data in */ - entry_p->te_data_size = dsize; - if (dsize > 0) { - if (table_p->ta_data_align == 0) - data_copy_p = ENTRY_DATA_BUF(table_p, entry_p); - else - data_copy_p = entry_data_buf(table_p, entry_p); - if (data_buf != NULL) - memcpy(data_copy_p, data_buf, dsize); - } - else - data_copy_p = NULL; - if (key_buf_p != NULL) - *key_buf_p = key_copy_p; - if (data_buf_p != NULL) - *data_buf_p = data_copy_p; - /* insert into list, no need to append */ - entry_p->te_next_p = table_p->ta_buckets[bucket]; - table_p->ta_buckets[bucket] = entry_p; - - table_p->ta_entry_n++; - - /* do we need auto-adjust? */ - if (table_p->ta_flags & TABLE_FLAG_AUTO_ADJUST - && SHOULD_TABLE_GROW(table_p)) - return table_adjust(table_p, table_p->ta_entry_n); - return TABLE_ERROR_NONE; -} - -/* - * int table_insert - * - * DESCRIPTION: - * - * Exactly the same as table_insert_kd except it does not pass back a - * pointer to the key after they have been inserted into the table - * structure. This is still here for backwards compatibility. - * - * See table_insert_kd for more information. - * - * RETURNS: - * - * Success - TABLE_ERROR_NONE - * - * Failure - Table error code. - * - * ARGUMENTS: - * - * table_p - Table structure pointer into which we will be inserting a - * new key/data pair. - * - * key_buf - Buffer of bytes of the key that we are inserting. If you - * are storing an (int) as the key (for example) then key_buf should - * be a (int *). - * - * key_size - Size of the key_buf buffer. If set to < 0 then the - * library will do a strlen of key_buf and add 1 for the '\0'. If you - * are storing an (int) as the key (for example) then key_size should - * be sizeof(int). - * - * data_buf - Buffer of bytes of the data that we are inserting. If - * it is NULL then the library will allocate space for the data in the - * table without copying in any information. If data_buf is NULL and - * data_size is 0 then the library will associate a NULL data pointer - * with the key. If you are storing a (long) as the data (for - * example) then data_buf should be a (long *). - * - * data_size - Size of the data_buf buffer. If set to < 0 then the - * library will do a strlen of data_buf and add 1 for the '\0'. If - * you are storing an (long) as the key (for example) then key_size - * should be sizeof(long). - * - * data_buf_p - Pointer which, if not NULL, will be set to the address - * of the data storage that was allocated in the table. If you are - * storing an (long) as the data (for example) then data_buf_p should - * be (long **) i.e. the address of a (long *). - * - * overwrite - Flag which, if set to 1, will allow the overwriting of - * the data in the table with the new data if the key already exists - * in the table. - */ -int table_insert(table_t * table_p, - const void *key_buf, const int key_size, - const void *data_buf, const int data_size, - void **data_buf_p, const char overwrite_b) -{ - return table_insert_kd(table_p, key_buf, key_size, data_buf, data_size, - NULL, data_buf_p, overwrite_b); -} - -/* - * int table_retrieve - * - * DESCRIPTION: - * - * This routine looks up a key made up of a buffer of bytes and an - * associated size in the table. If found then it returns the - * associated data information. - * - * RETURNS: - * - * Success - TABLE_ERROR_NONE - * - * Failure - Table error code. - * - * ARGUMENTS: - * - * table_p - Table structure pointer into which we will be searching - * for the key. - * - * key_buf - Buffer of bytes of the key that we are searching for. If - * you are looking for an (int) as the key (for example) then key_buf - * should be a (int *). - * - * key_size - Size of the key_buf buffer. If set to < 0 then the - * library will do a strlen of key_buf and add 1 for the '\0'. If you - * are looking for an (int) as the key (for example) then key_size - * should be sizeof(int). - * - * data_buf_p - Pointer which, if not NULL, will be set to the address - * of the data storage that was allocated in the table and that is - * associated with the key. If a (long) was stored as the data (for - * example) then data_buf_p should be (long **) i.e. the address of a - * (long *). - * - * data_size_p - Pointer to an integer which, if not NULL, will be set - * to the size of the data stored in the table that is associated with - * the key. - */ -int table_retrieve(table_t * table_p, - const void *key_buf, const int key_size, - void **data_buf_p, int *data_size_p) -{ - int bucket; - unsigned int ksize; - table_entry_t *entry_p, **buckets; - - if (table_p == NULL) - return TABLE_ERROR_ARG_NULL; - if (table_p->ta_magic != TABLE_MAGIC) - return TABLE_ERROR_PNT; - if (key_buf == NULL) - return TABLE_ERROR_ARG_NULL; - /* find key size */ - if (key_size < 0) - ksize = strlen((char *) key_buf) + sizeof(char); - else - ksize = key_size; - /* get the bucket number via a has function */ - bucket = hash(key_buf, ksize, 0) % table_p->ta_bucket_n; - - /* look for the entry in this bucket, only check keys of the same size */ - buckets = table_p->ta_buckets; - for (entry_p = buckets[bucket]; - entry_p != NULL; - entry_p = entry_p->te_next_p) { - entry_p = TABLE_POINTER(table_p, table_entry_t *, entry_p); - if (entry_p->te_key_size == ksize - && memcmp(ENTRY_KEY_BUF(entry_p), key_buf, ksize) == 0) - break; - } - - /* not found? */ - if (entry_p == NULL) - return TABLE_ERROR_NOT_FOUND; - if (data_buf_p != NULL) { - if (entry_p->te_data_size == 0) - *data_buf_p = NULL; - else { - if (table_p->ta_data_align == 0) - *data_buf_p = ENTRY_DATA_BUF(table_p, entry_p); - else - *data_buf_p = entry_data_buf(table_p, entry_p); - } - } - if (data_size_p != NULL) - *data_size_p = entry_p->te_data_size; - return TABLE_ERROR_NONE; -} - -/* - * int table_delete - * - * DESCRIPTION: - * - * This routine looks up a key made up of a buffer of bytes and an - * associated size in the table. If found then it will be removed - * from the table. The associated data can be passed back to the user - * if requested. - * - * RETURNS: - * - * Success - TABLE_ERROR_NONE - * - * Failure - Table error code. - * - * NOTE: this could be an allocation error if the library is to return - * the data to the user. - * - * ARGUMENTS: - * - * table_p - Table structure pointer from which we will be deleteing - * the key. - * - * key_buf - Buffer of bytes of the key that we are searching for to - * delete. If you are deleting an (int) key (for example) then - * key_buf should be a (int *). - * - * key_size - Size of the key_buf buffer. If set to < 0 then the - * library will do a strlen of key_buf and add 1 for the '\0'. If you - * are deleting an (int) key (for example) then key_size should be - * sizeof(int). - * - * data_buf_p - Pointer which, if not NULL, will be set to the address - * of the data storage that was allocated in the table and that was - * associated with the key. If a (long) was stored as the data (for - * example) then data_buf_p should be (long **) i.e. the address of a - * (long *). If a pointer is passed in, the caller is responsible for - * freeing it after use. If data_buf_p is NULL then the library will - * free up the data allocation itself. - * - * data_size_p - Pointer to an integer which, if not NULL, will be set - * to the size of the data that was stored in the table and that was - * associated with the key. - */ -int table_delete(table_t * table_p, - const void *key_buf, const int key_size, - void **data_buf_p, int *data_size_p) -{ - int bucket; - unsigned int ksize; - unsigned char *data_copy_p; - table_entry_t *entry_p, *last_p; - - if (table_p == NULL) - return TABLE_ERROR_ARG_NULL; - if (table_p->ta_magic != TABLE_MAGIC) - return TABLE_ERROR_PNT; - if (key_buf == NULL) - return TABLE_ERROR_ARG_NULL; - /* get the key size */ - if (key_size < 0) - ksize = strlen((char *) key_buf) + sizeof(char); - else - ksize = key_size; - /* find our bucket */ - bucket = hash(key_buf, ksize, 0) % table_p->ta_bucket_n; - - /* look for the entry in this bucket, only check keys of the same size */ - for (last_p = NULL, entry_p = table_p->ta_buckets[bucket]; entry_p != NULL; - last_p = entry_p, entry_p = entry_p->te_next_p) { - if (entry_p->te_key_size == ksize - && memcmp(ENTRY_KEY_BUF(entry_p), key_buf, ksize) == 0) - break; - } - - /* did we find it? */ - if (entry_p == NULL) - return TABLE_ERROR_NOT_FOUND; - /* - * NOTE: we may want to adjust the linear counters here if the entry - * we are deleting is the one we are pointing on or is ahead of the - * one in the bucket list - */ - - /* remove entry from the linked list */ - if (last_p == NULL) - table_p->ta_buckets[bucket] = entry_p->te_next_p; - else - last_p->te_next_p = entry_p->te_next_p; - /* free entry */ - if (data_buf_p != NULL) { - if (entry_p->te_data_size == 0) - *data_buf_p = NULL; - else { - /* - * if we were storing it compacted, we now need to malloc some - * space if the user wants the value after the delete. - */ - *data_buf_p = table_p->ta_malloc(table_p->opt_param, - entry_p->te_data_size); - if (*data_buf_p == NULL) - return TABLE_ERROR_ALLOC; - if (table_p->ta_data_align == 0) - data_copy_p = ENTRY_DATA_BUF(table_p, entry_p); - else - data_copy_p = entry_data_buf(table_p, entry_p); - memcpy(*data_buf_p, data_copy_p, entry_p->te_data_size); - } - } - if (data_size_p != NULL) - *data_size_p = entry_p->te_data_size; - table_p->ta_free(table_p->opt_param, entry_p); - entry_p = NULL; - - table_p->ta_entry_n--; - - /* do we need auto-adjust down? */ - if ((table_p->ta_flags & TABLE_FLAG_AUTO_ADJUST) - && (table_p->ta_flags & TABLE_FLAG_ADJUST_DOWN) - && SHOULD_TABLE_SHRINK(table_p)) - return table_adjust(table_p, table_p->ta_entry_n); - return TABLE_ERROR_NONE; -} - -/* - * int table_delete_first - * - * DESCRIPTION: - * - * This is like the table_delete routines except it deletes the first - * key/data pair in the table instead of an entry corresponding to a - * particular key. The associated key and data information can be - * passed back to the user if requested. This routines is handy to - * clear out a table. - * - * RETURNS: - * - * Success - TABLE_ERROR_NONE - * - * Failure - Table error code. - * - * NOTE: this could be an allocation error if the library is to return - * the data to the user. - * - * ARGUMENTS: - * - * table_p - Table structure pointer from which we will be deleteing - * the first key. - * - * key_buf_p - Pointer which, if not NULL, will be set to the address - * of the storage of the first key that was allocated in the table. - * If an (int) was stored as the first key (for example) then - * key_buf_p should be (int **) i.e. the address of a (int *). If a - * pointer is passed in, the caller is responsible for freeing it - * after use. If key_buf_p is NULL then the library will free up the - * key allocation itself. - * - * key_size_p - Pointer to an integer which, if not NULL, will be set - * to the size of the key that was stored in the table and that was - * associated with the key. - * - * data_buf_p - Pointer which, if not NULL, will be set to the address - * of the data storage that was allocated in the table and that was - * associated with the key. If a (long) was stored as the data (for - * example) then data_buf_p should be (long **) i.e. the address of a - * (long *). If a pointer is passed in, the caller is responsible for - * freeing it after use. If data_buf_p is NULL then the library will - * free up the data allocation itself. - * - * data_size_p - Pointer to an integer which, if not NULL, will be set - * to the size of the data that was stored in the table and that was - * associated with the key. - */ -int table_delete_first(table_t * table_p, - void **key_buf_p, int *key_size_p, - void **data_buf_p, int *data_size_p) -{ - unsigned char *data_copy_p; - table_entry_t *entry_p; - table_linear_t linear; - - if (table_p == NULL) - return TABLE_ERROR_ARG_NULL; - if (table_p->ta_magic != TABLE_MAGIC) - return TABLE_ERROR_PNT; - /* take the first entry */ - entry_p = first_entry(table_p, &linear); - if (entry_p == NULL) - return TABLE_ERROR_NOT_FOUND; - /* - * NOTE: we may want to adjust the linear counters here if the entry - * we are deleting is the one we are pointing on or is ahead of the - * one in the bucket list - */ - - /* remove entry from the linked list */ - table_p->ta_buckets[linear.tl_bucket_c] = entry_p->te_next_p; - - /* free entry */ - if (key_buf_p != NULL) { - if (entry_p->te_key_size == 0) - *key_buf_p = NULL; - else { - /* - * if we were storing it compacted, we now need to malloc some - * space if the user wants the value after the delete. - */ - *key_buf_p = table_p->ta_malloc(table_p->opt_param, - entry_p->te_key_size); - if (*key_buf_p == NULL) - return TABLE_ERROR_ALLOC; - memcpy(*key_buf_p, ENTRY_KEY_BUF(entry_p), entry_p->te_key_size); - } - } - if (key_size_p != NULL) - *key_size_p = entry_p->te_key_size; - if (data_buf_p != NULL) { - if (entry_p->te_data_size == 0) - *data_buf_p = NULL; - else { - /* - * if we were storing it compacted, we now need to malloc some - * space if the user wants the value after the delete. - */ - *data_buf_p = table_p->ta_malloc(table_p->opt_param, - entry_p->te_data_size); - if (*data_buf_p == NULL) - return TABLE_ERROR_ALLOC; - if (table_p->ta_data_align == 0) - data_copy_p = ENTRY_DATA_BUF(table_p, entry_p); - else - data_copy_p = entry_data_buf(table_p, entry_p); - memcpy(*data_buf_p, data_copy_p, entry_p->te_data_size); - } - } - if (data_size_p != NULL) - *data_size_p = entry_p->te_data_size; - table_p->ta_free(table_p->opt_param, entry_p); - - table_p->ta_entry_n--; - - /* do we need auto-adjust down? */ - if ((table_p->ta_flags & TABLE_FLAG_AUTO_ADJUST) - && (table_p->ta_flags & TABLE_FLAG_ADJUST_DOWN) - && SHOULD_TABLE_SHRINK(table_p)) - return table_adjust(table_p, table_p->ta_entry_n); - return TABLE_ERROR_NONE; -} - -/* - * int table_info - * - * DESCRIPTION: - * - * Get some information about a table_p structure. - * - * RETURNS: - * - * Success - TABLE_ERROR_NONE - * - * Failure - Table error code. - * - * ARGUMENTS: - * - * table_p - Table structure pointer from which we are getting - * information. - * - * num_buckets_p - Pointer to an integer which, if not NULL, will - * contain the number of buckets in the table. - * - * num_entries_p - Pointer to an integer which, if not NULL, will - * contain the number of entries stored in the table. - */ -int table_info(table_t * table_p, int *num_buckets_p, int *num_entries_p) -{ - if (table_p == NULL) - return TABLE_ERROR_ARG_NULL; - if (table_p->ta_magic != TABLE_MAGIC) - return TABLE_ERROR_PNT; - if (num_buckets_p != NULL) - *num_buckets_p = table_p->ta_bucket_n; - if (num_entries_p != NULL) - *num_entries_p = table_p->ta_entry_n; - return TABLE_ERROR_NONE; -} - -/* - * int table_adjust - * - * DESCRIPTION: - * - * Set the number of buckets in a table to a certain value. - * - * RETURNS: - * - * Success - TABLE_ERROR_NONE - * - * Failure - Table error code. - * - * ARGUMENTS: - * - * table_p - Table structure pointer of which we are adjusting. - * - * bucket_n - Number buckets to adjust the table to. Set to 0 to - * adjust the table to its number of entries. - */ -int table_adjust(table_t * table_p, const int bucket_n) -{ - table_entry_t *entry_p, *next_p; - table_entry_t **buckets, **bucket_p, **bounds_p; - int bucket; - unsigned int buck_n; - - if (table_p == NULL) - return TABLE_ERROR_ARG_NULL; - if (table_p->ta_magic != TABLE_MAGIC) - return TABLE_ERROR_PNT; - /* - * NOTE: we walk through the entries and rehash them. If we stored - * the hash value as a full int in the table-entry, all we would - * have to do is remod it. - */ - - /* normalize to the number of entries */ - if (bucket_n == 0) - buck_n = table_p->ta_entry_n; - else - buck_n = bucket_n; - /* we must have at least 1 bucket */ - if (buck_n == 0) - buck_n = 1; - /* make sure we have somethign to do */ - if (buck_n <= table_p->ta_bucket_n) - return TABLE_ERROR_NONE; - /* allocate a new bucket list */ - buckets = (table_entry_t **) - table_p->ta_calloc(table_p->opt_param, - buck_n, sizeof(table_entry_t *)); - if (table_p->ta_buckets == NULL) - return TABLE_ERROR_ALLOC; - /* - * run through each of the items in the current table and rehash - * them into the newest bucket sizes - */ - bounds_p = table_p->ta_buckets + table_p->ta_bucket_n; - for (bucket_p = table_p->ta_buckets; bucket_p < bounds_p; bucket_p++) { - for (entry_p = *bucket_p; entry_p != NULL; entry_p = next_p) { - - /* hash the old data into the new table size */ - bucket = hash(ENTRY_KEY_BUF(entry_p), entry_p->te_key_size, 0) % buck_n; - - /* record the next one now since we overwrite next below */ - next_p = entry_p->te_next_p; - - /* insert into new list, no need to append */ - entry_p->te_next_p = buckets[bucket]; - buckets[bucket] = entry_p; - - /* - * NOTE: we may want to adjust the bucket_c linear entry here to - * keep it current - */ - } - /* remove the old table pointers as we go by */ - *bucket_p = NULL; - } - - /* replace the table buckets with the new ones */ - table_p->ta_free(table_p->opt_param, table_p->ta_buckets); - table_p->ta_buckets = buckets; - table_p->ta_bucket_n = buck_n; - - return TABLE_ERROR_NONE; -} - -/* - * const char *table_strerror - * - * DESCRIPTION: - * - * Return the corresponding string for the error number. - * - * RETURNS: - * - * Success - String equivalient of the error. - * - * Failure - String "invalid error code" - * - * ARGUMENTS: - * - * error - Error number that we are converting. - */ -const char *table_strerror(const int error) -{ - error_str_t *err_p; - - for (err_p = errors; err_p->es_error != 0; err_p++) { - if (err_p->es_error == error) - return err_p->es_string; - } - - return INVALID_ERROR; -} - -/* - * int table_type_size - * - * DESCRIPTION: - * - * Return the size of the internal table type. - * - * RETURNS: - * - * The size of the table_t type. - * - * ARGUMENTS: - * - * None. - */ -int table_type_size(void) -{ - return sizeof(table_t); -} - -/************************* linear access routines ****************************/ - -/* - * int table_first - * - * DESCRIPTION: - * - * Find first element in a table and pass back information about the - * key/data pair. If any of the key/data pointers are NULL then they - * are ignored. - * - * NOTE: This function is not reentrant. More than one thread cannot - * be doing a first and next on the same table at the same time. Use - * the table_first_r version below for this. - * - * RETURNS: - * - * Success - TABLE_ERROR_NONE - * - * Failure - Table error code. - * - * ARGUMENTS: - * - * table_p - Table structure pointer from which we are getting the - * first element. - * - * key_buf_p - Pointer which, if not NULL, will be set to the address - * of the storage of the first key that is allocated in the table. If - * an (int) is stored as the first key (for example) then key_buf_p - * should be (int **) i.e. the address of a (int *). - * - * key_size_p - Pointer to an integer which, if not NULL, will be set - * to the size of the key that is stored in the table and that is - * associated with the first key. - * - * data_buf_p - Pointer which, if not NULL, will be set to the address - * of the data storage that is allocated in the table and that is - * associated with the first key. If a (long) is stored as the data - * (for example) then data_buf_p should be (long **) i.e. the address - * of a (long *). - * - * data_size_p - Pointer to an integer which, if not NULL, will be set - * to the size of the data that is stored in the table and that is - * associated with the first key. - */ -int table_first(table_t * table_p, - void **key_buf_p, int *key_size_p, - void **data_buf_p, int *data_size_p) -{ - table_entry_t *entry_p; - - if (table_p == NULL) - return TABLE_ERROR_ARG_NULL; - if (table_p->ta_magic != TABLE_MAGIC) - return TABLE_ERROR_PNT; - /* initialize our linear magic number */ - table_p->ta_linear.tl_magic = LINEAR_MAGIC; - - entry_p = first_entry(table_p, &table_p->ta_linear); - if (entry_p == NULL) - return TABLE_ERROR_NOT_FOUND; - if (key_buf_p != NULL) - *key_buf_p = ENTRY_KEY_BUF(entry_p); - if (key_size_p != NULL) - *key_size_p = entry_p->te_key_size; - if (data_buf_p != NULL) { - if (entry_p->te_data_size == 0) - *data_buf_p = NULL; - else { - if (table_p->ta_data_align == 0) - *data_buf_p = ENTRY_DATA_BUF(table_p, entry_p); - else - *data_buf_p = entry_data_buf(table_p, entry_p); - } - } - if (data_size_p != NULL) - *data_size_p = entry_p->te_data_size; - return TABLE_ERROR_NONE; -} - -/* - * int table_next - * - * DESCRIPTION: - * - * Find the next element in a table and pass back information about - * the key/data pair. If any of the key/data pointers are NULL then - * they are ignored. - * - * NOTE: This function is not reentrant. More than one thread cannot - * be doing a first and next on the same table at the same time. Use - * the table_next_r version below for this. - * - * RETURNS: - * - * Success - TABLE_ERROR_NONE - * - * Failure - Table error code. - * - * ARGUMENTS: - * - * table_p - Table structure pointer from which we are getting the - * next element. - * - * key_buf_p - Pointer which, if not NULL, will be set to the address - * of the storage of the next key that is allocated in the table. If - * an (int) is stored as the next key (for example) then key_buf_p - * should be (int **) i.e. the address of a (int *). - * - * key_size_p - Pointer to an integer which, if not NULL, will be set - * to the size of the key that is stored in the table and that is - * associated with the next key. - * - * data_buf_p - Pointer which, if not NULL, will be set to the address - * of the data storage that is allocated in the table and that is - * associated with the next key. If a (long) is stored as the data - * (for example) then data_buf_p should be (long **) i.e. the address - * of a (long *). - * - * data_size_p - Pointer to an integer which, if not NULL, will be set - * to the size of the data that is stored in the table and that is - * associated with the next key. - */ -int table_next(table_t * table_p, - void **key_buf_p, int *key_size_p, - void **data_buf_p, int *data_size_p) -{ - table_entry_t *entry_p; - int error; - - if (table_p == NULL) - return TABLE_ERROR_ARG_NULL; - if (table_p->ta_magic != TABLE_MAGIC) - return TABLE_ERROR_PNT; - if (table_p->ta_linear.tl_magic != LINEAR_MAGIC) - return TABLE_ERROR_LINEAR; - /* move to the next entry */ - entry_p = next_entry(table_p, &table_p->ta_linear, &error); - if (entry_p == NULL) - return error; - if (key_buf_p != NULL) - *key_buf_p = ENTRY_KEY_BUF(entry_p); - if (key_size_p != NULL) - *key_size_p = entry_p->te_key_size; - if (data_buf_p != NULL) { - if (entry_p->te_data_size == 0) - *data_buf_p = NULL; - else { - if (table_p->ta_data_align == 0) - *data_buf_p = ENTRY_DATA_BUF(table_p, entry_p); - else - *data_buf_p = entry_data_buf(table_p, entry_p); - } - } - if (data_size_p != NULL) - *data_size_p = entry_p->te_data_size; - return TABLE_ERROR_NONE; -} - -/* - * int table_this - * - * DESCRIPTION: - * - * Find the current element in a table and pass back information about - * the key/data pair. If any of the key/data pointers are NULL then - * they are ignored. - * - * NOTE: This function is not reentrant. Use the table_current_r - * version below. - * - * RETURNS: - * - * Success - TABLE_ERROR_NONE - * - * Failure - Table error code. - * - * ARGUMENTS: - * - * table_p - Table structure pointer from which we are getting the - * current element. - * - * key_buf_p - Pointer which, if not NULL, will be set to the address - * of the storage of the current key that is allocated in the table. - * If an (int) is stored as the current key (for example) then - * key_buf_p should be (int **) i.e. the address of a (int *). - * - * key_size_p - Pointer to an integer which, if not NULL, will be set - * to the size of the key that is stored in the table and that is - * associated with the current key. - * - * data_buf_p - Pointer which, if not NULL, will be set to the address - * of the data storage that is allocated in the table and that is - * associated with the current key. If a (long) is stored as the data - * (for example) then data_buf_p should be (long **) i.e. the address - * of a (long *). - * - * data_size_p - Pointer to an integer which, if not NULL, will be set - * to the size of the data that is stored in the table and that is - * associated with the current key. - */ -int table_this(table_t * table_p, - void **key_buf_p, int *key_size_p, - void **data_buf_p, int *data_size_p) -{ - table_entry_t *entry_p = NULL; - int entry_c; - - if (table_p == NULL) - return TABLE_ERROR_ARG_NULL; - if (table_p->ta_magic != TABLE_MAGIC) - return TABLE_ERROR_PNT; - if (table_p->ta_linear.tl_magic != LINEAR_MAGIC) - return TABLE_ERROR_LINEAR; - /* if we removed an item that shorted the bucket list, we may get this */ - if (table_p->ta_linear.tl_bucket_c >= table_p->ta_bucket_n) { - /* - * NOTE: this might happen if we delete an item which shortens the - * table bucket numbers. - */ - return TABLE_ERROR_NOT_FOUND; - } - - /* find the entry which is the nth in the list */ - entry_p = table_p->ta_buckets[table_p->ta_linear.tl_bucket_c]; - /* NOTE: we swap the order here to be more efficient */ - for (entry_c = table_p->ta_linear.tl_entry_c; entry_c > 0; entry_c--) { - /* did we reach the end of the list? */ - if (entry_p == NULL) - break; - entry_p = TABLE_POINTER(table_p, table_entry_t *, entry_p)->te_next_p; - } - - /* is this a NOT_FOUND or a LINEAR error */ - if (entry_p == NULL) - return TABLE_ERROR_NOT_FOUND; - if (key_buf_p != NULL) - *key_buf_p = ENTRY_KEY_BUF(entry_p); - if (key_size_p != NULL) - *key_size_p = entry_p->te_key_size; - if (data_buf_p != NULL) { - if (entry_p->te_data_size == 0) - *data_buf_p = NULL; - else { - if (table_p->ta_data_align == 0) - *data_buf_p = ENTRY_DATA_BUF(table_p, entry_p); - else - *data_buf_p = entry_data_buf(table_p, entry_p); - } - } - if (data_size_p != NULL) - *data_size_p = entry_p->te_data_size; - return TABLE_ERROR_NONE; -} - -/* - * int table_first_r - * - * DESCRIPTION: - * - * Reetrant version of the table_first routine above. Find first - * element in a table and pass back information about the key/data - * pair. If any of the key/data pointers are NULL then they are - * ignored. - * - * RETURNS: - * - * Success - TABLE_ERROR_NONE - * - * Failure - Table error code. - * - * ARGUMENTS: - * - * table_p - Table structure pointer from which we are getting the - * first element. - * - * linear_p - Pointer to a table linear structure which is initialized - * here. The same pointer should then be passed to table_next_r - * below. - * - * key_buf_p - Pointer which, if not NULL, will be set to the address - * of the storage of the first key that is allocated in the table. If - * an (int) is stored as the first key (for example) then key_buf_p - * should be (int **) i.e. the address of a (int *). - * - * key_size_p - Pointer to an integer which, if not NULL, will be set - * to the size of the key that is stored in the table and that is - * associated with the first key. - * - * data_buf_p - Pointer which, if not NULL, will be set to the address - * of the data storage that is allocated in the table and that is - * associated with the first key. If a (long) is stored as the data - * (for example) then data_buf_p should be (long **) i.e. the address - * of a (long *). - * - * data_size_p - Pointer to an integer which, if not NULL, will be set - * to the size of the data that is stored in the table and that is - * associated with the first key. - */ -int table_first_r(table_t * table_p, table_linear_t * linear_p, - void **key_buf_p, int *key_size_p, - void **data_buf_p, int *data_size_p) -{ - table_entry_t *entry_p; - - if (table_p == NULL) - return TABLE_ERROR_ARG_NULL; - if (table_p->ta_magic != TABLE_MAGIC) - return TABLE_ERROR_PNT; - if (linear_p == NULL) - return TABLE_ERROR_ARG_NULL; - /* initialize our linear magic number */ - linear_p->tl_magic = LINEAR_MAGIC; - - entry_p = first_entry(table_p, linear_p); - if (entry_p == NULL) - return TABLE_ERROR_NOT_FOUND; - if (key_buf_p != NULL) - *key_buf_p = ENTRY_KEY_BUF(entry_p); - if (key_size_p != NULL) - *key_size_p = entry_p->te_key_size; - if (data_buf_p != NULL) { - if (entry_p->te_data_size == 0) - *data_buf_p = NULL; - else { - if (table_p->ta_data_align == 0) - *data_buf_p = ENTRY_DATA_BUF(table_p, entry_p); - else - *data_buf_p = entry_data_buf(table_p, entry_p); - } - } - if (data_size_p != NULL) - *data_size_p = entry_p->te_data_size; - return TABLE_ERROR_NONE; -} - -/* - * int table_next_r - * - * DESCRIPTION: - * - * Reetrant version of the table_next routine above. Find next - * element in a table and pass back information about the key/data - * pair. If any of the key/data pointers are NULL then they are - * ignored. - * - * RETURNS: - * - * Success - TABLE_ERROR_NONE - * - * Failure - Table error code. - * - * ARGUMENTS: - * - * table_p - Table structure pointer from which we are getting the - * next element. - * - * linear_p - Pointer to a table linear structure which is incremented - * here. The same pointer must have been passed to table_first_r - * first so that it can be initialized. - * - * key_buf_p - Pointer which, if not NULL, will be set to the address - * of the storage of the next key that is allocated in the table. If - * an (int) is stored as the next key (for example) then key_buf_p - * should be (int **) i.e. the address of a (int *). - * - * key_size_p - Pointer to an integer which, if not NULL will be set - * to the size of the key that is stored in the table and that is - * associated with the next key. - * - * data_buf_p - Pointer which, if not NULL, will be set to the address - * of the data storage that is allocated in the table and that is - * associated with the next key. If a (long) is stored as the data - * (for example) then data_buf_p should be (long **) i.e. the address - * of a (long *). - * - * data_size_p - Pointer to an integer which, if not NULL, will be set - * to the size of the data that is stored in the table and that is - * associated with the next key. - */ -int table_next_r(table_t * table_p, table_linear_t * linear_p, - void **key_buf_p, int *key_size_p, - void **data_buf_p, int *data_size_p) -{ - table_entry_t *entry_p; - int error; - - if (table_p == NULL) - return TABLE_ERROR_ARG_NULL; - if (table_p->ta_magic != TABLE_MAGIC) - return TABLE_ERROR_PNT; - if (linear_p == NULL) - return TABLE_ERROR_ARG_NULL; - if (linear_p->tl_magic != LINEAR_MAGIC) - return TABLE_ERROR_LINEAR; - /* move to the next entry */ - entry_p = next_entry(table_p, linear_p, &error); - if (entry_p == NULL) - return error; - if (key_buf_p != NULL) - *key_buf_p = ENTRY_KEY_BUF(entry_p); - if (key_size_p != NULL) - *key_size_p = entry_p->te_key_size; - if (data_buf_p != NULL) { - if (entry_p->te_data_size == 0) - *data_buf_p = NULL; - else { - if (table_p->ta_data_align == 0) - *data_buf_p = ENTRY_DATA_BUF(table_p, entry_p); - else - *data_buf_p = entry_data_buf(table_p, entry_p); - } - } - if (data_size_p != NULL) - *data_size_p = entry_p->te_data_size; - return TABLE_ERROR_NONE; -} - -/* - * int table_this_r - * - * DESCRIPTION: - * - * Reetrant version of the table_this routine above. Find current - * element in a table and pass back information about the key/data - * pair. If any of the key/data pointers are NULL then they are - * ignored. - * - * RETURNS: - * - * Success - TABLE_ERROR_NONE - * - * Failure - Table error code. - * - * ARGUMENTS: - * - * table_p - Table structure pointer from which we are getting the - * current element. - * - * linear_p - Pointer to a table linear structure which is accessed - * here. The same pointer must have been passed to table_first_r - * first so that it can be initialized. - * - * key_buf_p - Pointer which, if not NULL, will be set to the address - * of the storage of the current key that is allocated in the table. - * If an (int) is stored as the current key (for example) then - * key_buf_p should be (int **) i.e. the address of a (int *). - * - * key_size_p - Pointer to an integer which, if not NULL, will be set - * to the size of the key that is stored in the table and that is - * associated with the current key. - * - * data_buf_p - Pointer which, if not NULL, will be set to the address - * of the data storage that is allocated in the table and that is - * associated with the current key. If a (long) is stored as the data - * (for example) then data_buf_p should be (long **) i.e. the address - * of a (long *). - * - * data_size_p - Pointer to an integer which, if not NULL, will be set - * to the size of the data that is stored in the table and that is - * associated with the current key. - */ -int table_this_r(table_t * table_p, table_linear_t * linear_p, - void **key_buf_p, int *key_size_p, - void **data_buf_p, int *data_size_p) -{ - table_entry_t *entry_p; - int entry_c; - - if (table_p == NULL) - return TABLE_ERROR_ARG_NULL; - if (table_p->ta_magic != TABLE_MAGIC) - return TABLE_ERROR_PNT; - if (linear_p->tl_magic != LINEAR_MAGIC) - return TABLE_ERROR_LINEAR; - /* if we removed an item that shorted the bucket list, we may get this */ - if (linear_p->tl_bucket_c >= table_p->ta_bucket_n) { - /* - * NOTE: this might happen if we delete an item which shortens the - * table bucket numbers. - */ - return TABLE_ERROR_NOT_FOUND; - } - - /* find the entry which is the nth in the list */ - for (entry_c = linear_p->tl_entry_c, - entry_p = table_p->ta_buckets[linear_p->tl_bucket_c]; - entry_p != NULL && entry_c > 0; - entry_c--, entry_p = TABLE_POINTER(table_p, table_entry_t *, - entry_p)->te_next_p) { - } - - if (entry_p == NULL) - return TABLE_ERROR_NOT_FOUND; - if (key_buf_p != NULL) - *key_buf_p = ENTRY_KEY_BUF(entry_p); - if (key_size_p != NULL) - *key_size_p = entry_p->te_key_size; - if (data_buf_p != NULL) { - if (entry_p->te_data_size == 0) - *data_buf_p = NULL; - else { - if (table_p->ta_data_align == 0) - *data_buf_p = ENTRY_DATA_BUF(table_p, entry_p); - else - *data_buf_p = entry_data_buf(table_p, entry_p); - } - } - if (data_size_p != NULL) - *data_size_p = entry_p->te_data_size; - return TABLE_ERROR_NONE; -} - -/******************************** table order ********************************/ - -/* - * table_entry_t *table_order - * - * DESCRIPTION: - * - * Order a table by building an array of table entry pointers and then - * sorting this array using the qsort function. To retrieve the - * sorted entries, you can then use the table_entry routine to access - * each entry in order. - * - * NOTE: This routine is now thread safe in that two table_order calls - * can now happen at the same time, even on the same table. - * - * RETURNS: - * - * An allocated list of entry pointers which must be freed later. - * Returns null on error. - * - * ARGUMENTS: - * - * table_p - Pointer to the table that we are ordering. - * - * compare - Comparison function defined by the user. Its definition - * is at the top of the table.h file. If this is NULL then it will - * order the table my memcmp-ing the keys. - * - * num_entries_p - Pointer to an integer which, if not NULL, will - * contain the number of entries in the returned entry pointer array. - * - * error_p - Pointer to an integer which, if not NULL, will contain a - * table error code. - */ -table_entry_t **table_order(table_t * table_p, table_compare_t compare, - int *num_entries_p, int *error_p) -{ - table_entry_t *entry_p, **entries, **entries_p; - table_linear_t linear; - compare_t comp_func; - int error; - - if (table_p == NULL) { - if (error_p != NULL) - *error_p = TABLE_ERROR_ARG_NULL; - return NULL; - } - if (table_p->ta_magic != TABLE_MAGIC) { - if (error_p != NULL) - *error_p = TABLE_ERROR_PNT; - return NULL; - } - - /* there must be at least 1 element in the table for this to work */ - if (table_p->ta_entry_n == 0) { - if (error_p != NULL) - *error_p = TABLE_ERROR_EMPTY; - return NULL; - } - - entries = (table_entry_t **) - table_p->ta_malloc(table_p->opt_param, - table_p->ta_entry_n *sizeof(table_entry_t *)); - if (entries == NULL) { - if (error_p != NULL) - *error_p = TABLE_ERROR_ALLOC; - return NULL; - } - - /* get a pointer to all entries */ - entry_p = first_entry(table_p, &linear); - if (entry_p == NULL) { - if (error_p != NULL) - *error_p = TABLE_ERROR_NOT_FOUND; - return NULL; - } - - /* add all of the entries to the array */ - for (entries_p = entries; - entry_p != NULL; - entry_p = next_entry(table_p, &linear, &error)) - *entries_p++ = entry_p; - if (error != TABLE_ERROR_NOT_FOUND) { - if (error_p != NULL) - *error_p = error; - return NULL; - } - - if (compare == NULL) { - /* this is regardless of the alignment */ - comp_func = local_compare; - } - else if (table_p->ta_data_align == 0) - comp_func = external_compare; - else - comp_func = external_compare_align; - /* now qsort the entire entries array from first to last element */ - split(entries, entries + table_p->ta_entry_n - 1, comp_func, compare, - table_p); - - if (num_entries_p != NULL) - *num_entries_p = table_p->ta_entry_n; - if (error_p != NULL) - *error_p = TABLE_ERROR_NONE; - return entries; -} - -/* - * int table_entry - * - * DESCRIPTION: - * - * Get information about an element. The element is one from the - * array returned by the table_order function. If any of the key/data - * pointers are NULL then they are ignored. - * - * RETURNS: - * - * Success - TABLE_ERROR_NONE - * - * Failure - Table error code. - * - * ARGUMENTS: - * - * table_p - Table structure pointer from which we are getting the - * element. - * - * entry_p - Pointer to a table entry from the array returned by the - * table_order function. - * - * key_buf_p - Pointer which, if not NULL, will be set to the address - * of the storage of this entry that is allocated in the table. If an - * (int) is stored as this entry (for example) then key_buf_p should - * be (int **) i.e. the address of a (int *). - * - * key_size_p - Pointer to an integer which, if not NULL, will be set - * to the size of the key that is stored in the table. - * - * data_buf_p - Pointer which, if not NULL, will be set to the address - * of the data storage of this entry that is allocated in the table. - * If a (long) is stored as this entry data (for example) then - * data_buf_p should be (long **) i.e. the address of a (long *). - * - * data_size_p - Pointer to an integer which, if not NULL, will be set - * to the size of the data that is stored in the table. - */ -int table_entry_info(table_t * table_p, table_entry_t * entry_p, - void **key_buf_p, int *key_size_p, - void **data_buf_p, int *data_size_p) -{ - if (table_p == NULL) - return TABLE_ERROR_ARG_NULL; - if (table_p->ta_magic != TABLE_MAGIC) - return TABLE_ERROR_PNT; - if (entry_p == NULL) - return TABLE_ERROR_ARG_NULL; - if (key_buf_p != NULL) - *key_buf_p = ENTRY_KEY_BUF(entry_p); - if (key_size_p != NULL) - *key_size_p = entry_p->te_key_size; - if (data_buf_p != NULL) { - if (entry_p->te_data_size == 0) - *data_buf_p = NULL; - else { - if (table_p->ta_data_align == 0) - *data_buf_p = ENTRY_DATA_BUF(table_p, entry_p); - else - *data_buf_p = entry_data_buf(table_p, entry_p); - } - } - if (data_size_p != NULL) - *data_size_p = entry_p->te_data_size; - return TABLE_ERROR_NONE; -} - diff --git a/modules/ssl/ssl_util_table.h b/modules/ssl/ssl_util_table.h deleted file mode 100644 index e14a0ee991..0000000000 --- a/modules/ssl/ssl_util_table.h +++ /dev/null @@ -1,185 +0,0 @@ -/* _ _ -** _ __ ___ ___ __| | ___ ___| | mod_ssl -** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL -** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org -** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org -** |_____| -** ssl_util_table.h -** High Performance Hash Table Header -*/ - -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2003 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" must - * not be used to endorse or promote products derived from this - * software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache", - * nor may "Apache" appear in their name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 THE APACHE SOFTWARE FOUNDATION OR - * ITS 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. - * ==================================================================== - */ - -/* - * Generic hash table defines - * Table 4.1.0 July-28-1998 - * - * This library is a generic open hash table with buckets and - * linked lists. It is pretty high performance. Each element - * has a key and a data. The user indexes on the key to find the - * data. - * - * Copyright 1998 by Gray Watson - * - * Permission to use, copy, modify, and distribute this software for any - * purpose and without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies, - * and that the name of Gray Watson not be used in advertising or - * publicity pertaining to distribution of the document or software - * without specific, written prior permission. - * - * Gray Watson makes no representations about the suitability of the - * software described herein for any purpose. It is provided "as is" - * without express or implied warranty. - */ - -#ifndef __SSL_UTIL_TABLE_H__ -#define __SSL_UTIL_TABLE_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* - * To build a "key" in any of the below routines, pass in a pointer to - * the key and its size [i.e. sizeof(int), etc]. With any of the - * "key" or "data" arguments, if their size is < 0, it will do an - * internal strlen of the item and add 1 for the \0. - * - * If you are using firstkey() and nextkey() functions, be careful if, - * after starting your firstkey loop, you use delete or insert, it - * will not crash but may produce interesting results. If you are - * deleting from firstkey to NULL it will work fine. - */ - -/* return types for table functions */ -#define TABLE_ERROR_NONE 1 /* no error from function */ -#define TABLE_ERROR_PNT 2 /* bad table pointer */ -#define TABLE_ERROR_ARG_NULL 3 /* buffer args were null */ -#define TABLE_ERROR_SIZE 4 /* size of data was bad */ -#define TABLE_ERROR_OVERWRITE 5 /* key exists and we cant overwrite */ -#define TABLE_ERROR_NOT_FOUND 6 /* key does not exist */ -#define TABLE_ERROR_ALLOC 7 /* memory allocation error */ -#define TABLE_ERROR_LINEAR 8 /* no linear access started */ -#define TABLE_ERROR_OPEN 9 /* could not open file */ -#define TABLE_ERROR_SEEK 10 /* could not seek to pos in file */ -#define TABLE_ERROR_READ 11 /* could not read from file */ -#define TABLE_ERROR_WRITE 12 /* could not write to file */ -#define TABLE_ERROR_EMPTY 13 /* table is empty */ -#define TABLE_ERROR_NOT_EMPTY 14 /* table contains data */ -#define TABLE_ERROR_ALIGNMENT 15 /* invalid alignment value */ - -/* - * Table flags set with table_attr. - */ - -/* - * Automatically adjust the number of table buckets on the fly. - * Whenever the number of entries gets above some threshold, the - * number of buckets is realloced to a new size and each entry is - * re-hashed. Although this may take some time when it re-hashes, the - * table will perform better over time. - */ -#define TABLE_FLAG_AUTO_ADJUST (1<<0) - -/* - * If the above auto-adjust flag is set, also adjust the number of - * table buckets down as we delete entries. - */ -#define TABLE_FLAG_ADJUST_DOWN (1<<1) - -/* structure to walk through the fields in a linear order */ -typedef struct { - unsigned int tl_magic; /* magic structure to ensure correct init */ - unsigned int tl_bucket_c; /* where in the table buck array we are */ - unsigned int tl_entry_c; /* in the bucket, which entry we are on */ -} table_linear_t; - -typedef int (*table_compare_t)(const void *key1, const int key1_size, - const void *data1, const int data1_size, - const void *key2, const int key2_size, - const void *data2, const int data2_size); - -#ifndef TABLE_PRIVATE -typedef void table_t; -typedef void table_entry_t; -#endif - -/* - * Prototypes - */ -extern table_t *table_alloc(const unsigned int bucket_n, int *error_p, void *(*malloc_f)(void *opt_param, size_t size), void *(*calloc_f)(void *opt_param, size_t number, size_t size), void *(*realloc_f)(void *opt_param, void *ptr, size_t size), void (*free_f)(void *opt_param, void *ptr), void *opt_param); -extern int table_attr(table_t *table_p, const int attr); -extern int table_set_data_alignment(table_t *table_p, const int alignment); -extern int table_clear(table_t *table_p); -extern int table_free(table_t *table_p); -extern int table_insert_kd(table_t *table_p, const void *key_buf, const int key_size, const void *data_buf, const int data_size, void **key_buf_p, void **data_buf_p, const char overwrite_b); -extern int table_insert(table_t *table_p, const void *key_buf, const int key_size, const void *data_buf, const int data_size, void **data_buf_p, const char overwrite_b); -extern int table_retrieve(table_t *table_p, const void *key_buf, const int key_size, void **data_buf_p, int *data_size_p); -extern int table_delete(table_t *table_p, const void *key_buf, const int key_size, void **data_buf_p, int *data_size_p); -extern int table_delete_first(table_t *table_p, void **key_buf_p, int *key_size_p, void **data_buf_p, int *data_size_p); -extern int table_info(table_t *table_p, int *num_buckets_p, int *num_entries_p); -extern int table_adjust(table_t *table_p, const int bucket_n); -extern const char *table_strerror(const int error); -extern int table_type_size(void); -extern int table_first(table_t *table_p, void **key_buf_p, int *key_size_p, void **data_buf_p, int *data_size_p); -extern int table_next(table_t *table_p, void **key_buf_p, int *key_size_p, void **data_buf_p, int *data_size_p); -extern int table_this(table_t *table_p, void **key_buf_p, int *key_size_p, void **data_buf_p, int *data_size_p); -extern int table_first_r(table_t *table_p, table_linear_t *linear_p, void **key_buf_p, int *key_size_p, void **data_buf_p, int *data_size_p); -extern int table_next_r(table_t *table_p, table_linear_t *linear_p, void **key_buf_p, int *key_size_p, void **data_buf_p, int *data_size_p); -extern int table_this_r(table_t *table_p, table_linear_t *linear_p, void **key_buf_p, int *key_size_p, void **data_buf_p, int *data_size_p); -extern table_entry_t **table_order(table_t *table_p, table_compare_t compare, int *num_entries_p, int *error_p); -extern int table_entry_info(table_t *table_p, table_entry_t *entry_p, void **key_buf_p, int *key_size_p, void **data_buf_p, int *data_size_p); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __SSL_UTIL_TABLE_H__ */