1
0
mirror of https://github.com/apache/httpd.git synced 2025-08-07 04:02:58 +03:00
Obtained from:
Submitted by:   Madhusudan Mathihalli <madhusudan_mathihalli@hp.com>
Reviewed by:	dougm
implement SSLSessionCache shmht and shmcb based on apr_rmm and apr_shm


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@93942 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Doug MacEachern
2002-03-14 23:31:23 +00:00
parent 008ca7d056
commit 97b148c3b5
8 changed files with 286 additions and 237 deletions

View File

@@ -1,5 +1,8 @@
Changes with Apache 2.0.34-dev
*) implement SSLSessionCache shmht and shmcb based on apr_rmm and
apr_shm. [Madhusudan Mathihalli <madhusudan_mathihalli@hp.com>]
*) Fix apxs -g handling. Move config_vars.mk from the top build
directory to the build directory. PR 10163 [Jeff Trawick]

View File

@@ -108,6 +108,8 @@
#include "apr_fnmatch.h"
#include "apr_strings.h"
#include "apr_dbm.h"
#include "apr_rmm.h"
#include "apr_shm.h"
#include "apr_optional.h"
/* OpenSSL headers */
@@ -488,9 +490,8 @@ typedef struct {
int nSessionCacheMode;
char *szSessionCacheDataFile;
int nSessionCacheDataSize;
#if 0 /* XXX */
AP_MM *pSessionCacheDataMM;
#endif
apr_shm_t *pSessionCacheDataMM;
apr_rmm_t *pSessionCacheDataRMM;
apr_table_t *tSessionCacheDataTable;
ssl_mutexmode_t nMutexMode;
char *szMutexFile;
@@ -679,22 +680,22 @@ SSL_SESSION *ssl_scache_dbm_retrieve(server_rec *, UCHAR *, int);
void ssl_scache_dbm_remove(server_rec *, UCHAR *, int);
void ssl_scache_dbm_expire(server_rec *);
void ssl_scache_dbm_status(server_rec *, apr_pool_t *, void (*)(char *, void *), void *);
#if 0 /* XXX */
void ssl_scache_shmht_init(server_rec *, pool *);
void ssl_scache_shmht_init(server_rec *, apr_pool_t *);
void ssl_scache_shmht_kill(server_rec *);
BOOL ssl_scache_shmht_store(server_rec *, UCHAR *, int, time_t, SSL_SESSION *);
SSL_SESSION *ssl_scache_shmht_retrieve(server_rec *, UCHAR *, int);
void ssl_scache_shmht_remove(server_rec *, UCHAR *, int);
void ssl_scache_shmht_expire(server_rec *);
void ssl_scache_shmht_status(server_rec *, pool *, void (*)(char *, void *), void *);
void ssl_scache_shmcb_init(server_rec *, pool *);
void ssl_scache_shmht_status(server_rec *, apr_pool_t *, void (*)(char *, void *), void *);
void ssl_scache_shmcb_init(server_rec *, apr_pool_t *);
void ssl_scache_shmcb_kill(server_rec *);
BOOL ssl_scache_shmcb_store(server_rec *, UCHAR *, int, time_t, SSL_SESSION *);
SSL_SESSION *ssl_scache_shmcb_retrieve(server_rec *, UCHAR *, int);
void ssl_scache_shmcb_remove(server_rec *, UCHAR *, int);
void ssl_scache_shmcb_expire(server_rec *);
void ssl_scache_shmcb_status(server_rec *, pool *, void (*)(char *, void *), void *);
#endif
void ssl_scache_shmcb_status(server_rec *, apr_pool_t *, void (*)(char *, void *), void *);
/* Pass Phrase Support */
void ssl_pphrase_Handle(server_rec *, apr_pool_t *);
@@ -768,4 +769,5 @@ char *ssl_util_algotypestr(ssl_algo_t);
char *ssl_util_ptxtsub(apr_pool_t *, const char *, const char *, char *);
void ssl_util_thread_setup(server_rec *, apr_pool_t *);
#define APR_SHM_MAXSIZE (64 * 1024 * 1024)
#endif /* __MOD_SSL_H__ */

View File

@@ -95,9 +95,8 @@ SSLModConfigRec *ssl_config_global_create(server_rec *s)
mc->nSessionCacheMode = SSL_SCMODE_UNSET;
mc->szSessionCacheDataFile = NULL;
mc->nSessionCacheDataSize = 0;
#if 0 /* XXX */
mc->pSessionCacheDataMM = NULL;
#endif
mc->pSessionCacheDataRMM = NULL;
mc->tSessionCacheDataTable = NULL;
mc->nMutexMode = SSL_MUTEXMODE_UNSET;
mc->szMutexFile = NULL;
@@ -803,6 +802,9 @@ const char *ssl_cmd_SSLVerifyDepth(cmd_parms *cmd, void *ctx,
return NULL;
}
#define MODSSL_NO_SHARED_MEMORY_ERROR \
"SSLSessionCache: shared memory cache not useable on this platform"
const char *ssl_cmd_SSLSessionCache(cmd_parms *cmd, void *ctx,
const char *arg)
{
@@ -828,16 +830,10 @@ const char *ssl_cmd_SSLSessionCache(cmd_parms *cmd, void *ctx,
mc->nSessionCacheMode = SSL_SCMODE_DBM;
mc->szSessionCacheDataFile = ap_server_root_relative(mc->pPool, arg+4);
}
else if (((arglen > 4) && strcEQn(arg, "shm:", 4)) ||
((arglen > 6) && strcEQn(arg, "shmht:", 6)))
{
#if 0 /* XXX */
if (!ap_mm_useable()) {
return "SSLSessionCache: shared memory cache "
"not useable on this platform";
}
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 =
@@ -862,13 +858,7 @@ const char *ssl_cmd_SSLSessionCache(cmd_parms *cmd, void *ctx,
"size has to be >= 8192 bytes";
}
#if 0 /* XXX */
maxsize = ap_mm_core_maxsegsize();
#else
maxsize = 1024 * 512;
#endif
if (mc->nSessionCacheDataSize >= maxsize) {
if (mc->nSessionCacheDataSize >= APR_SHM_MAXSIZE) {
return apr_psprintf(cmd->pool,
"SSLSessionCache: Invalid argument: "
"size has to be < %d bytes on this "
@@ -876,22 +866,22 @@ const char *ssl_cmd_SSLSessionCache(cmd_parms *cmd, void *ctx,
}
}
}
else if ((arglen > 6) && strcEQn(arg, "shmcb:", 6)) {
#if 0 /* XXX */
if (!ap_mm_useable()) {
return "SSLSessionCache: shared memory cache "
"not useable on this platform";
}
else if (((arglen > 4) && strcEQn(arg, "shm:", 4)) ||
((arglen > 6) && strcEQn(arg, "shmcb:", 6))) {
#if !APR_HAS_SHARED_MEMORY
return MODSSL_NO_SHARED_MEMORY_ERROR;
#endif
mc->nSessionCacheMode = SSL_SCMODE_SHMCB;
mc->szSessionCacheDataFile = ap_server_root_relative(mc->pPool, arg+6);
colon = ap_strchr_c(arg, ':');
mc->szSessionCacheDataFile =
ap_server_root_relative(mc->pPool, colon+1);
mc->tSessionCacheDataTable = NULL;
mc->nSessionCacheDataSize = 1024*512; /* 512KB */
if ((cp = strchr(mc->szSessionCacheDataFile, '('))) {
*cp++ = NUL;
if ((cp2 = strchr(cp, ')'))) {
if (!(cp2 = strchr(cp, ')'))) {
return "SSLSessionCache: Invalid argument: "
"no closing parenthesis";
}
@@ -906,13 +896,7 @@ const char *ssl_cmd_SSLSessionCache(cmd_parms *cmd, void *ctx,
}
#if 0 /* XXX */
maxsize = ap_mm_core_maxsegsize();
#else
maxsize = 1024 * 512;
#endif
if (mc->nSessionCacheDataSize >= maxsize) {
if (mc->nSessionCacheDataSize >= APR_SHM_MAXSIZE) {
return apr_psprintf(cmd->pool,
"SSLSessionCache: Invalid argument: "
"size has to be < %d bytes on this "

View File

@@ -75,12 +75,22 @@ void ssl_scache_init(server_rec *s, apr_pool_t *p)
if (mc->nSessionCacheMode == SSL_SCMODE_DBM)
ssl_scache_dbm_init(s, p);
#if 0 /* XXX */
else 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);
#endif
else if ((mc->nSessionCacheMode == SSL_SCMODE_SHMHT) ||
(mc->nSessionCacheMode == SSL_SCMODE_SHMCB)) {
void *data;
const char *userdata_key = "ssl_scache_init";
apr_pool_userdata_get(&data, userdata_key, s->process->pool);
if (!data) {
apr_pool_userdata_setn((const void *)1, userdata_key,
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);
}
return;
}
@@ -90,12 +100,10 @@ void ssl_scache_kill(server_rec *s)
if (mc->nSessionCacheMode == SSL_SCMODE_DBM)
ssl_scache_dbm_kill(s);
#if 0 /* XXX */
else if (mc->nSessionCacheMode == SSL_SCMODE_SHMHT)
ssl_scache_shmht_kill(s);
else if (mc->nSessionCacheMode == SSL_SCMODE_SHMCB)
ssl_scache_shmcb_kill(s);
#endif
return;
}
@@ -106,12 +114,10 @@ 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);
#if 0 /* XXX */
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);
#endif
return rv;
}
@@ -122,12 +128,10 @@ 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);
#if 0 /* XXX */
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);
#endif
return sess;
}
@@ -137,12 +141,10 @@ void ssl_scache_remove(server_rec *s, UCHAR *id, int idlen)
if (mc->nSessionCacheMode == SSL_SCMODE_DBM)
ssl_scache_dbm_remove(s, id, idlen);
#if 0 /* XXX */
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);
#endif
return;
}
@@ -152,12 +154,10 @@ 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);
#if 0 /* XXX */
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);
#endif
return;
}
@@ -167,12 +167,10 @@ void ssl_scache_expire(server_rec *s)
if (mc->nSessionCacheMode == SSL_SCMODE_DBM)
ssl_scache_dbm_expire(s);
#if 0 /* XXX */
else if (mc->nSessionCacheMode == SSL_SCMODE_SHMHT)
ssl_scache_shmht_expire(s);
else if (mc->nSessionCacheMode == SSL_SCMODE_SHMCB)
ssl_scache_shmcb_expire(s);
#endif
return;
}

View File

@@ -59,8 +59,6 @@
#include "mod_ssl.h"
#if 0 /* XXX */
/*
* This shared memory based SSL session cache implementation was
* originally written by Geoff Thorpe <geoff@eu.c2.net> for C2Net Europe
@@ -178,24 +176,6 @@
* so as to decrease "struct-bloat". sigh.
*/
typedef struct {
#if 0
unsigned char division_mask;
unsigned int division_offset;
unsigned int division_size;
unsigned int queue_size;
unsigned int index_num;
unsigned int index_offset;
unsigned int index_size;
unsigned int cache_data_offset;
unsigned int cache_data_size;
unsigned long num_stores;
unsigned long num_expiries;
unsigned long num_scrolled;
unsigned long num_retrieves_hit;
unsigned long num_retrieves_miss;
unsigned long num_removes_hit;
unsigned long num_removes_miss;
#else
unsigned long num_stores;
unsigned long num_expiries;
unsigned long num_scrolled;
@@ -208,11 +188,10 @@ typedef struct {
unsigned int queue_size;
unsigned int cache_data_offset;
unsigned int cache_data_size;
unsigned char division_mask;
unsigned int index_num;
unsigned int index_offset;
unsigned int index_size;
unsigned char division_mask;
#endif
} SHMCBHeader;
/*
@@ -262,13 +241,38 @@ typedef struct {
memcpys can hardly make a dent on the massive memmove operations this
cache technique avoids, nor the overheads of ASN en/decoding. */
static unsigned int shmcb_get_safe_uint(unsigned int *);
static void shmcb_set_safe_uint(unsigned int *, unsigned int);
static void shmcb_set_safe_uint_ex(unsigned char *, const unsigned char *);
#define shmcb_set_safe_uint(pdest, src) \
do { \
unsigned int tmp_uint = src; \
shmcb_set_safe_uint_ex((unsigned char *)pdest, \
(const unsigned char *)(&tmp_uint)); \
} while(0)
#if 0 /* Unused so far */
static unsigned long shmcb_get_safe_ulong(unsigned long *);
static void shmcb_set_safe_ulong(unsigned long *, unsigned long);
static void shmcb_set_safe_ulong_ex(unsigned char *, const unsigned char *);
#define shmcb_set_safe_ulong(pdest, src) \
do { \
unsigned long tmp_ulong = src; \
shmcb_set_safe_ulong_ex((unsigned char *)pdest, \
(const unsigned char *)(&tmp_ulong)); \
} while(0)
#endif
static time_t shmcb_get_safe_time(time_t *);
static void shmcb_set_safe_time(time_t *, time_t);
static void shmcb_set_safe_time_ex(unsigned char *, const unsigned char *);
#define shmcb_set_safe_time(pdest, src) \
do { \
time_t tmp_time = src; \
shmcb_set_safe_time_ex((unsigned char *)pdest, \
(const unsigned char *)(&tmp_time)); \
} while(0)
/* This is necessary simply so that the size passed to memset() is not a
* compile-time constant, preventing the compiler from optimising it. */
static void shmcb_safe_clear(void *ptr, size_t size)
{
memset(ptr, 0, size);
}
/* Underlying functions for session-caching */
static BOOL shmcb_init_memory(server_rec *, void *, unsigned int);
@@ -306,81 +310,65 @@ static BOOL shmcb_remove_session_id(server_rec *, SHMCBQueue *, SHMCBCache *, UC
static unsigned int shmcb_get_safe_uint(unsigned int *ptr)
{
unsigned char *from;
unsigned int ret;
from = (unsigned char *)ptr;
memcpy(&ret, from, sizeof(unsigned int));
shmcb_set_safe_uint_ex((unsigned char *)(&ret),
(const unsigned char *)ptr);
return ret;
}
static void shmcb_set_safe_uint(unsigned int *ptr, unsigned int val)
static void shmcb_set_safe_uint_ex(unsigned char *dest,
const unsigned char *src)
{
unsigned char *to, *from;
to = (unsigned char *)ptr;
from = (unsigned char *)(&val);
memcpy(to, from, sizeof(unsigned int));
memcpy(dest, src, sizeof(unsigned int));
}
#if 0 /* Unused so far */
static unsigned long shmcb_get_safe_ulong(unsigned long *ptr)
{
unsigned char *from;
unsigned long ret;
from = (unsigned char *)ptr;
memcpy(&ret, from, sizeof(unsigned long));
shmcb_set_safe_ulong_ex((unsigned char *)(&ret),
(const unsigned char *)ptr);
return ret;
}
static void shmcb_set_safe_ulong(unsigned long *ptr, unsigned long val)
static void shmcb_set_safe_ulong_ex(unsigned char *dest,
const unsigned char *src)
{
unsigned char *to, *from;
to = (unsigned char *)ptr;
from = (unsigned char *)(&val);
memcpy(to, from, sizeof(unsigned long));
memcpy(dest, src, sizeof(unsigned long));
}
#endif
static time_t shmcb_get_safe_time(time_t * ptr)
{
unsigned char *from;
time_t ret;
from = (unsigned char *)ptr;
memcpy(&ret, from, sizeof(time_t));
shmcb_set_safe_time_ex((unsigned char *)(&ret),
(const unsigned char *)ptr);
return ret;
}
static void shmcb_set_safe_time(time_t * ptr, time_t val)
static void shmcb_set_safe_time_ex(unsigned char *dest,
const unsigned char *src)
{
unsigned char *to, *from;
to = (unsigned char *)ptr;
from = (unsigned char *)(&val);
memcpy(to, from, sizeof(time_t));
memcpy(dest, src, sizeof(time_t));
}
/*
**
** High-Level "handlers" as per ssl_scache.c
**
*/
static void *shmcb_malloc(size_t size)
static void *shmcb_malloc(SSLModConfigRec *mc, size_t size)
{
SSLModConfigRec *mc = myModConfig();
return ap_mm_malloc(mc->pSessionCacheDataMM, size);
apr_rmm_off_t off = apr_rmm_malloc(mc->pSessionCacheDataRMM, size);
return apr_rmm_addr_get(mc->pSessionCacheDataRMM, off);
}
void ssl_scache_shmcb_init(server_rec *s, pool *p)
void ssl_scache_shmcb_init(server_rec *s, apr_pool_t *p)
{
SSLModConfigRec *mc = myModConfig();
AP_MM *mm;
SSLModConfigRec *mc = myModConfig(s);
void *shm_segment = NULL;
int avail, avail_orig;
apr_status_t rv;
/*
* Create shared memory segment
@@ -389,23 +377,29 @@ void ssl_scache_shmcb_init(server_rec *s, pool *p)
ssl_log(s, SSL_LOG_ERROR, "SSLSessionCache required");
ssl_die();
}
if ((mm = ap_mm_create(mc->nSessionCacheDataSize,
mc->szSessionCacheDataFile)) == NULL) {
if ((rv = apr_shm_create(&(mc->pSessionCacheDataMM),
mc->nSessionCacheDataSize,
mc->szSessionCacheDataFile,
mc->pPool)) != APR_SUCCESS) {
ssl_log(s, SSL_LOG_ERROR,
"Cannot allocate shared memory: %s", ap_mm_error());
"Cannot allocate shared memory: %d", rv);
ssl_die();
}
mc->pSessionCacheDataMM = mm;
/*
* Make sure the child processes have access to the underlying files
*/
ap_mm_permission(mm, SSL_MM_FILE_MODE, ap_user_id, -1);
if ((rv = apr_rmm_init(&(mc->pSessionCacheDataRMM), NULL,
apr_shm_baseaddr_get(mc->pSessionCacheDataMM),
mc->nSessionCacheDataSize,
mc->pPool)) != APR_SUCCESS) {
ssl_log(s, SSL_LOG_ERROR,
"Cannot initialize rmm: %d", rv);
ssl_die();
}
/*
* Create cache inside the shared memory segment
*/
avail = avail_orig = ap_mm_available(mm);
avail_orig = avail = mc->nSessionCacheDataSize - apr_rmm_overhead_get(0);
ssl_log(s, SSL_LOG_TRACE, "Shared-memory segment has %u available",
avail);
@@ -415,11 +409,11 @@ void ssl_scache_shmcb_init(server_rec *s, pool *p)
* and error and output trace information.
*/
while ((shm_segment == NULL) && ((avail_orig - avail) * 100 < avail_orig)) {
shm_segment = shmcb_malloc(avail);
shm_segment = shmcb_malloc(mc, avail);
if (shm_segment == NULL) {
ssl_log(s, SSL_LOG_TRACE,
"shmcb_malloc attempt for %u bytes failed", avail);
avail -= 2;
avail -= 4;
}
}
if (shm_segment == NULL) {
@@ -447,10 +441,15 @@ void ssl_scache_shmcb_init(server_rec *s, pool *p)
void ssl_scache_shmcb_kill(server_rec *s)
{
SSLModConfigRec *mc = myModConfig();
SSLModConfigRec *mc = myModConfig(s);
if (mc->pSessionCacheDataRMM != NULL) {
apr_rmm_destroy(mc->pSessionCacheDataRMM);
mc->pSessionCacheDataRMM = NULL;
}
if (mc->pSessionCacheDataMM != NULL) {
ap_mm_destroy(mc->pSessionCacheDataMM);
apr_shm_destroy(mc->pSessionCacheDataMM);
mc->pSessionCacheDataMM = NULL;
}
return;
@@ -459,7 +458,7 @@ void ssl_scache_shmcb_kill(server_rec *s)
BOOL ssl_scache_shmcb_store(server_rec *s, UCHAR *id, int idlen,
time_t timeout, SSL_SESSION * pSession)
{
SSLModConfigRec *mc = myModConfig();
SSLModConfigRec *mc = myModConfig(s);
void *shm_segment;
BOOL to_return = FALSE;
@@ -480,7 +479,7 @@ 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();
SSLModConfigRec *mc = myModConfig(s);
void *shm_segment;
SSL_SESSION *pSession;
@@ -501,7 +500,7 @@ 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();
SSLModConfigRec *mc = myModConfig(s);
void *shm_segment;
/* We've kludged our pointer into the other cache's member variable. */
@@ -517,10 +516,10 @@ void ssl_scache_shmcb_expire(server_rec *s)
return;
}
void ssl_scache_shmcb_status(server_rec *s, pool *p,
void ssl_scache_shmcb_status(server_rec *s, apr_pool_t *p,
void (*func) (char *, void *), void *arg)
{
SSLModConfigRec *mc = myModConfig();
SSLModConfigRec *mc = myModConfig(s);
SHMCBHeader *header;
SHMCBQueue queue;
SHMCBCache cache;
@@ -569,36 +568,36 @@ void ssl_scache_shmcb_status(server_rec *s, pool *p,
}
index_pct = (100 * total) / (header->index_num * (header->division_mask + 1));
cache_pct = (100 * cache_total) / (header->cache_data_size * (header->division_mask + 1));
func(ap_psprintf(p, "cache type: <b>SHMCB</b>, shared memory: <b>%d</b> "
func(apr_psprintf(p, "cache type: <b>SHMCB</b>, shared memory: <b>%d</b> "
"bytes, current sessions: <b>%d</b><br>",
mc->nSessionCacheDataSize, total), arg);
func(ap_psprintf(p, "sub-caches: <b>%d</b>, indexes per sub-cache: "
func(apr_psprintf(p, "sub-caches: <b>%d</b>, indexes per sub-cache: "
"<b>%d</b><br>", (int) header->division_mask + 1,
(int) header->index_num), arg);
if (non_empty_divisions != 0) {
average_expiry = (time_t)(expiry_total / (double)non_empty_divisions);
func(ap_psprintf(p, "time left on oldest entries' SSL sessions: "), arg);
func(apr_psprintf(p, "time left on oldest entries' SSL sessions: "), arg);
if (now < average_expiry)
func(ap_psprintf(p, "avg: <b>%d</b> seconds, (range: %d...%d)<br>",
func(apr_psprintf(p, "avg: <b>%d</b> seconds, (range: %d...%d)<br>",
(int)(average_expiry - now), (int) (min_expiry - now),
(int)(max_expiry - now)), arg);
else
func(ap_psprintf(p, "expiry threshold: <b>Calculation Error!</b>"
func(apr_psprintf(p, "expiry threshold: <b>Calculation Error!</b>"
"<br>"), arg);
}
func(ap_psprintf(p, "index usage: <b>%d%%</b>, cache usage: <b>%d%%</b>"
func(apr_psprintf(p, "index usage: <b>%d%%</b>, cache usage: <b>%d%%</b>"
"<br>", index_pct, cache_pct), arg);
func(ap_psprintf(p, "total sessions stored since starting: <b>%lu</b><br>",
func(apr_psprintf(p, "total sessions stored since starting: <b>%lu</b><br>",
header->num_stores), arg);
func(ap_psprintf(p, "total sessions expired since starting: <b>%lu</b><br>",
func(apr_psprintf(p,"total sessions expired since starting: <b>%lu</b><br>",
header->num_expiries), arg);
func(ap_psprintf(p, "total (pre-expiry) sessions scrolled out of the "
func(apr_psprintf(p, "total (pre-expiry) sessions scrolled out of the "
"cache: <b>%lu</b><br>", header->num_scrolled), arg);
func(ap_psprintf(p, "total retrieves since starting: <b>%lu</b> hit, "
func(apr_psprintf(p, "total retrieves since starting: <b>%lu</b> hit, "
"<b>%lu</b> miss<br>", header->num_retrieves_hit,
header->num_retrieves_miss), arg);
func(ap_psprintf(p, "total removes since starting: <b>%lu</b> hit, "
func(apr_psprintf(p, "total removes since starting: <b>%lu</b> hit, "
"<b>%lu</b> miss<br>", header->num_removes_hit,
header->num_removes_miss), arg);
ssl_log(s, SSL_LOG_TRACE, "leaving shmcb_status");
@@ -1342,6 +1341,3 @@ end:
ssl_log(s, SSL_LOG_TRACE, "leaving shmcb_remove_session_id");
return to_return;
}
#endif /* XXX */

View File

@@ -59,35 +59,46 @@
#include "mod_ssl.h"
#if 0 /* XXX */
/*
* 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(size_t size)
static void *ssl_scache_shmht_malloc(void *opt_param, size_t size)
{
SSLModConfigRec *mc = myModConfig();
return ap_mm_malloc(mc->pSessionCacheDataMM, 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(size_t number, size_t size)
static void *ssl_scache_shmht_calloc(void *opt_param,
size_t number, size_t size)
{
SSLModConfigRec *mc = myModConfig();
return ap_mm_calloc(mc->pSessionCacheDataMM, number, size);
SSLModConfigRec *mc = myModConfig((server_rec *)opt_param);
apr_rmm_off_t off = apr_rmm_calloc(mc->pSessionCacheDataRMM, (number*size));
ssl_log((server_rec *)opt_param, SSL_LOG_ERROR,
"rmm calloc returning %ld %ld size %d",
off, apr_rmm_addr_get(mc->pSessionCacheDataRMM, off), (number * size));
return apr_rmm_addr_get(mc->pSessionCacheDataRMM, off);
}
static void *ssl_scache_shmht_realloc(void *ptr, size_t size)
static void *ssl_scache_shmht_realloc(void *opt_param, void *ptr, size_t size)
{
SSLModConfigRec *mc = myModConfig();
return ap_mm_realloc(mc->pSessionCacheDataMM, ptr, 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 *ptr)
static void ssl_scache_shmht_free(void *opt_param, void *ptr)
{
SSLModConfigRec *mc = myModConfig();
ap_mm_free(mc->pSessionCacheDataMM, 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;
}
@@ -96,14 +107,14 @@ static void ssl_scache_shmht_free(void *ptr)
* based on a hash table inside a shared memory segment.
*/
void ssl_scache_shmht_init(server_rec *s, pool *p)
void ssl_scache_shmht_init(server_rec *s, apr_pool_t *p)
{
SSLModConfigRec *mc = myModConfig();
AP_MM *mm;
SSLModConfigRec *mc = myModConfig(s);
table_t *ta;
int ta_errno;
int avail;
apr_size_t avail;
int n;
apr_status_t rv;
/*
* Create shared memory segment
@@ -112,35 +123,47 @@ void ssl_scache_shmht_init(server_rec *s, pool *p)
ssl_log(s, SSL_LOG_ERROR, "SSLSessionCache required");
ssl_die();
}
if ((mm = ap_mm_create(mc->nSessionCacheDataSize,
mc->szSessionCacheDataFile)) == NULL) {
if ((rv = apr_shm_create(&(mc->pSessionCacheDataMM),
mc->nSessionCacheDataSize,
mc->szSessionCacheDataFile, mc->pPool)) != APR_SUCCESS) {
ssl_log(s, SSL_LOG_ERROR,
"Cannot allocate shared memory: %s", ap_mm_error());
"Cannot allocate shared memory: %d", rv);
ssl_die();
}
mc->pSessionCacheDataMM = mm;
/*
* Make sure the childs have access to the underlaying files
*/
ap_mm_permission(mm, SSL_MM_FILE_MODE, ap_user_id, -1);
if ((rv = apr_rmm_init(&(mc->pSessionCacheDataRMM), NULL,
apr_shm_baseaddr_get(mc->pSessionCacheDataMM),
mc->nSessionCacheDataSize, mc->pPool)) != APR_SUCCESS) {
ssl_log(s, SSL_LOG_ERROR,
"Cannot initialize rmm: %d", rv);
ssl_die();
}
ssl_log(s, SSL_LOG_ERROR, "initialize MM %ld RMM %ld",
mc->pSessionCacheDataMM, mc->pSessionCacheDataRMM);
/*
* Create hash table in shared memory segment
*/
avail = ap_mm_available(mm);
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 )) == NULL) {
ssl_scache_shmht_free, s )) == NULL) {
ssl_log(s, SSL_LOG_ERROR,
"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);
@@ -157,10 +180,15 @@ void ssl_scache_shmht_init(server_rec *s, pool *p)
void ssl_scache_shmht_kill(server_rec *s)
{
SSLModConfigRec *mc = myModConfig();
SSLModConfigRec *mc = myModConfig(s);
if (mc->pSessionCacheDataRMM != NULL) {
apr_rmm_destroy(mc->pSessionCacheDataRMM);
mc->pSessionCacheDataRMM = NULL;
}
if (mc->pSessionCacheDataMM != NULL) {
ap_mm_destroy(mc->pSessionCacheDataMM);
apr_shm_destroy(mc->pSessionCacheDataMM);
mc->pSessionCacheDataMM = NULL;
}
return;
@@ -168,7 +196,7 @@ void ssl_scache_shmht_kill(server_rec *s)
BOOL ssl_scache_shmht_store(server_rec *s, UCHAR *id, int idlen, time_t expiry, SSL_SESSION *sess)
{
SSLModConfigRec *mc = myModConfig();
SSLModConfigRec *mc = myModConfig(s);
void *vp;
UCHAR ucaData[SSL_SESSION_MAX_DER];
int nData;
@@ -199,7 +227,7 @@ BOOL ssl_scache_shmht_store(server_rec *s, UCHAR *id, int idlen, time_t expiry,
SSL_SESSION *ssl_scache_shmht_retrieve(server_rec *s, UCHAR *id, int idlen)
{
SSLModConfigRec *mc = myModConfig();
SSLModConfigRec *mc = myModConfig(s);
void *vp;
SSL_SESSION *sess = NULL;
UCHAR *ucpData;
@@ -245,7 +273,7 @@ SSL_SESSION *ssl_scache_shmht_retrieve(server_rec *s, UCHAR *id, int idlen)
void ssl_scache_shmht_remove(server_rec *s, UCHAR *id, int idlen)
{
SSLModConfigRec *mc = myModConfig();
SSLModConfigRec *mc = myModConfig(s);
/* remove value under key in table */
ssl_mutex_on(s);
@@ -256,7 +284,7 @@ void ssl_scache_shmht_remove(server_rec *s, UCHAR *id, int idlen)
void ssl_scache_shmht_expire(server_rec *s)
{
SSLModConfigRec *mc = myModConfig();
SSLModConfigRec *mc = myModConfig(s);
SSLSrvConfigRec *sc = mySrvConfig(s);
static time_t tLast = 0;
table_linear_t iterator;
@@ -292,6 +320,10 @@ void ssl_scache_shmht_expire(server_rec *s)
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;
}
@@ -305,16 +337,18 @@ void ssl_scache_shmht_expire(server_rec *s)
nDeleted++;
}
} while (rc == TABLE_ERROR_NONE);
/* (vpKeyThis != vpKey) && (nKeyThis != nKey) */
}
ssl_mutex_off(s);
ssl_log(s, SSL_LOG_TRACE, "Inter-Process Session Cache (SHMHT) Expiry: "
"old: %d, new: %d, removed: %d", nElements, nElements-nDeleted, nDeleted);
"old: %d, new: %d, removed: %d",
nElements, nElements-nDeleted, nDeleted);
return;
}
void ssl_scache_shmht_status(server_rec *s, pool *p, void (*func)(char *, void *), void *arg)
void ssl_scache_shmht_status(server_rec *s, apr_pool_t *p, void (*func)(char *, void *), void *arg)
{
SSLModConfigRec *mc = myModConfig();
SSLModConfigRec *mc = myModConfig(s);
void *vpKey;
void *vpData;
int nKey;
@@ -334,18 +368,15 @@ void ssl_scache_shmht_status(server_rec *s, pool *p, void (*func)(char *, void *
nElem += 1;
nSize += nData;
} while (table_next(mc->tSessionCacheDataTable,
&vpKey, &nKey, &vpData, &nData) == TABLE_ERROR_NONE);
&vpKey, &nKey, &vpData, &nData) == TABLE_ERROR_NONE);
}
ssl_mutex_off(s);
if (nSize > 0 && nElem > 0)
nAverage = nSize / nElem;
else
nAverage = 0;
func(ap_psprintf(p, "cache type: <b>SHMHT</b>, maximum size: <b>%d</b> bytes<br>", mc->nSessionCacheDataSize), arg);
func(ap_psprintf(p, "current sessions: <b>%d</b>, current size: <b>%d</b> bytes<br>", nElem, nSize), arg);
func(ap_psprintf(p, "average session size: <b>%d</b> bytes<br>", nAverage), arg);
func(apr_psprintf(p, "cache type: <b>SHMHT</b>, maximum size: <b>%d</b> bytes<br>", mc->nSessionCacheDataSize), arg);
func(apr_psprintf(p, "current sessions: <b>%d</b>, current size: <b>%d</b> bytes<br>", nElem, nSize), arg);
func(apr_psprintf(p, "average session size: <b>%d</b> bytes<br>", nAverage), arg);
return;
}
#endif /* XXX */

View File

@@ -96,6 +96,7 @@ typedef struct table_entry_st table_entry_t;
#define TABLE_PRIVATE
#include "ssl_util_table.h"
#include "mod_ssl.h"
/****************************** local defines ******************************/
@@ -205,10 +206,11 @@ struct table_st {
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)(size_t size);
void *(*ta_calloc)(size_t number, size_t size);
void *(*ta_realloc)(void *ptr, size_t size);
void (*ta_free)(void *ptr);
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 */
@@ -249,6 +251,28 @@ static error_str_t errors[] =
#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 ******************************/
/*
@@ -804,17 +828,17 @@ static void split(void *first_p, void *last_p, compare_t compare,
* and free(3)-style functions.
*/
table_t *table_alloc(const unsigned int bucket_n, int *error_p,
void *(*malloc_f)(size_t size),
void *(*calloc_f)(size_t number, size_t size),
void *(*realloc_f)(void *ptr, size_t size),
void (*free_f)(void *ptr))
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(sizeof(table_t));
table_p = malloc_f(opt_param, sizeof(table_t));
else
table_p = malloc(sizeof(table_t));
if (table_p == NULL) {
@@ -829,14 +853,15 @@ table_t *table_alloc(const unsigned int bucket_n, int *error_p,
buck_n = DEFAULT_SIZE;
/* allocate the buckets which are NULLed */
if (calloc_f != NULL)
table_p->ta_buckets = (table_entry_t **)calloc_f(buck_n, sizeof(table_entry_t *));
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(table_p);
free_f(opt_param, table_p);
else
free(table_p);
return NULL;
@@ -852,10 +877,11 @@ table_t *table_alloc(const unsigned int bucket_n, int *error_p,
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 : malloc;
table_p->ta_calloc = calloc_f != NULL ? calloc_f : calloc;
table_p->ta_realloc = realloc_f != NULL ? realloc_f : realloc;
table_p->ta_free = free_f != NULL ? free_f : free;
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;
@@ -972,13 +998,14 @@ int table_clear(table_t * table_p)
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 (bucket_p = table_p->ta_buckets; bucket_p <= bounds_p; bucket_p++) {
#if 0
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(entry_p);
table_p->ta_free(table_p->opt_param, entry_p);
}
#endif
/* clear the bucket entry after we free its entries */
*bucket_p = NULL;
}
@@ -1020,9 +1047,9 @@ int table_free(table_t * table_p)
ret = table_clear(table_p);
if (table_p->ta_buckets != NULL)
table_p->ta_free(table_p->ta_buckets);
table_p->ta_free(table_p->opt_param, table_p->ta_buckets);
table_p->ta_magic = 0;
table_p->ta_free(table_p);
table_p->ta_free(table_p->opt_param, table_p);
return ret;
}
@@ -1140,7 +1167,7 @@ int table_insert_kd(table_t * table_p,
/* 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 != 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)
@@ -1186,10 +1213,9 @@ int table_insert_kd(table_t * table_p,
* this may change any previous data_key_p and data_copy_p
* pointers.
*/
entry_p = (table_entry_t *) table_p->ta_realloc(entry_p,
entry_size(table_p,
entry_p->te_key_size,
dsize));
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 */
@@ -1222,7 +1248,9 @@ int table_insert_kd(table_t * table_p,
*/
/* allocate a new entry */
entry_p = (table_entry_t *) table_p->ta_malloc(entry_size(table_p, ksize, dsize));
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 */
@@ -1509,7 +1537,8 @@ int table_delete(table_t * table_p,
* 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(entry_p->te_data_size);
*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)
@@ -1521,7 +1550,8 @@ int table_delete(table_t * table_p,
}
if (data_size_p != NULL)
*data_size_p = entry_p->te_data_size;
table_p->ta_free(entry_p);
table_p->ta_free(table_p->opt_param, entry_p);
entry_p = NULL;
table_p->ta_entry_n--;
@@ -1616,7 +1646,8 @@ int table_delete_first(table_t * table_p,
* 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(entry_p->te_key_size);
*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);
@@ -1632,7 +1663,8 @@ int table_delete_first(table_t * table_p,
* 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(entry_p->te_data_size);
*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)
@@ -1644,7 +1676,7 @@ int table_delete_first(table_t * table_p,
}
if (data_size_p != NULL)
*data_size_p = entry_p->te_data_size;
table_p->ta_free(entry_p);
table_p->ta_free(table_p->opt_param, entry_p);
table_p->ta_entry_n--;
@@ -1739,10 +1771,12 @@ int table_adjust(table_t * table_p, const int bucket_n)
if (buck_n == 0)
buck_n = 1;
/* make sure we have somethign to do */
if (buck_n == table_p->ta_bucket_n)
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(buck_n, sizeof(table_entry_t *));
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;
/*
@@ -1773,7 +1807,7 @@ int table_adjust(table_t * table_p, const int bucket_n)
}
/* replace the table buckets with the new ones */
table_p->ta_free(table_p->ta_buckets);
table_p->ta_free(table_p->opt_param, table_p->ta_buckets);
table_p->ta_buckets = buckets;
table_p->ta_bucket_n = buck_n;
@@ -2402,8 +2436,9 @@ table_entry_t **table_order(table_t * table_p, table_compare_t compare,
return NULL;
}
entries = (table_entry_t **) table_p->ta_malloc(table_p->ta_entry_n *
sizeof(table_entry_t *));
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;

View File

@@ -155,7 +155,7 @@ typedef void table_entry_t;
/*
* Prototypes
*/
extern table_t *table_alloc(const unsigned int bucket_n, int *error_p, void *(*malloc_f)(size_t size), void *(*calloc_f)(size_t number, size_t size), void *(*realloc_f)(void *ptr, size_t size), void (*free_f)(void *ptr));
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);