From 8dacb0388763ec4da5198b2d6063b45067e16c21 Mon Sep 17 00:00:00 2001 From: olavmrk Date: Fri, 20 Jun 2014 11:24:38 +0000 Subject: Introduce dynamic memory pool for sessions This pool has a fixed size and the aim is to avoid arbitrary limits on entry's components, while maintaining an overall fixed entry size. Accessors function for a storage unit are provided for future use. Signed-off-by: Simo Sorce git-svn-id: https://modmellon.googlecode.com/svn/trunk@231 a716ebb1-153a-0410-b759-cfb97c6a1b53 --- README | 7 ++++ auth_mellon.h | 14 ++++++++ auth_mellon_cache.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++ auth_mellon_config.c | 12 +++++++ mod_auth_mellon.c | 6 +++- 5 files changed, 132 insertions(+), 1 deletion(-) diff --git a/README b/README index eb48deb..2381713 100644 --- a/README +++ b/README @@ -97,6 +97,13 @@ for mod_auth_mellon. The following is an example configuration: # Default: MellonCacheSize 100 MellonCacheSize 100 +# MellonCacheEntrySize sets the maximum size for a single session entry in +# bytes. When mod_auth_mellon reaches this limit, it cannot store any more +# data in the session and will return an error. The minimum entry size is +# 65536 bytes, values lower than that will be ignored and the minimum will +# be used. +# Default: MellonCacheEntrySize 196608 + # MellonLockFile is the full path to a file used for synchronizing access # to the session data. The path should only be used by one instance of # apache at a time. The server must be restarted before any changes to this diff --git a/auth_mellon.h b/auth_mellon.h index 8347013..5156851 100644 --- a/auth_mellon.h +++ b/auth_mellon.h @@ -78,6 +78,8 @@ #define AM_CACHE_MAX_LASSO_IDENTITY_SIZE 1024 #define AM_CACHE_MAX_LASSO_SESSION_SIZE 32768 #define AM_CACHE_MAX_LASSO_SAML_RESPONSE_SIZE 65536 +#define AM_CACHE_DEFAULT_ENTRY_SIZE 196608 +#define AM_CACHE_MIN_ENTRY_SIZE 65536 /* This is the length of the id we use (for session IDs and @@ -101,12 +103,15 @@ typedef struct am_mod_cfg_rec { int post_count; apr_size_t post_size; + int entry_size; + /* These variables can't be allowed to change after the session store * has been initialized. Therefore we copy them before initializing * the session store. */ int init_cache_size; const char *init_lock_file; + apr_size_t init_entry_size; apr_shm_t *cache; apr_global_mutex_t *lock; @@ -240,6 +245,9 @@ typedef struct am_dir_cfg_rec { LassoServer *server; } am_dir_cfg_rec; +typedef struct am_cache_storage_t { + apr_uintptr_t ptr; +} am_cache_storage_t; typedef struct am_cache_env_t { char varname[AM_CACHE_VARSIZE]; @@ -262,6 +270,10 @@ typedef struct am_cache_entry_t { char lasso_saml_response[AM_CACHE_MAX_LASSO_SAML_RESPONSE_SIZE]; am_cache_env_t env[AM_CACHE_ENVSIZE]; + + apr_size_t pool_size; + apr_size_t pool_used; + char pool[]; } am_cache_entry_t; typedef enum { @@ -322,6 +334,8 @@ void am_cookie_delete(request_rec *r); am_cache_entry_t *am_cache_lock(server_rec *s, am_cache_key_t type, const char *key); +const char *am_cache_entry_get_string(am_cache_entry_t *e, + am_cache_storage_t *slot); am_cache_entry_t *am_cache_new(server_rec *s, const char *key); void am_cache_unlock(server_rec *s, am_cache_entry_t *entry); diff --git a/auth_mellon_cache.c b/auth_mellon_cache.c index 3923569..0d64a82 100644 --- a/auth_mellon_cache.c +++ b/auth_mellon_cache.c @@ -113,6 +113,96 @@ am_cache_entry_t *am_cache_lock(server_rec *s, return NULL; } +static inline void am_cache_storage_null(am_cache_storage_t *slot) +{ + slot->ptr = 0; +} + +static inline apr_size_t am_cache_entry_pool_left(am_cache_entry_t *e) +{ + return e->pool_size - e->pool_used; +} + +static inline apr_size_t am_cache_entry_pool_size(am_mod_cfg_rec *cfg) +{ + return cfg->init_entry_size - sizeof(am_cache_entry_t); +} + +/* This function sets a string into the specified storage on the entry. + * + * NOTE: The string pointer may be NULL, in that case storage is freed + * and set to NULL. + * + * Parametrs: + * am_cache_entry_t *entry Pointer to an entry + * am_cache_storage_t *slot Pointer to storage + * const char *string Pointer to a replacement string + * + * Returns: + * 0 on success, HTTP_INTERNAL_SERVER_ERROR on error. + */ +static int am_cache_entry_store_string(am_cache_entry_t *entry, + am_cache_storage_t *slot, + const char *string) +{ + char *datastr = NULL; + apr_size_t datalen = 0; + apr_size_t str_len = 0; + + if (string == NULL) return 0; + + if (slot->ptr != 0) { + datastr = &entry->pool[slot->ptr]; + datalen = strlen(datastr) + 1; + } + str_len = strlen(string) + 1; + if (str_len - datalen <= 0) { + memcpy(datastr, string, str_len); + return 0; + } + + /* recover space if slot happens to point to the last allocated space */ + if (slot->ptr + datalen == entry->pool_used) { + entry->pool_used -= datalen; + slot->ptr = 0; + } + + if (am_cache_entry_pool_left(entry) < str_len) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, + "apr_cache_entry_store_string() asked %zd available: %zd. " + "It may be a good idea to increase MellonCacheEntrySize.", + str_len, am_cache_entry_pool_left(entry)); + return HTTP_INTERNAL_SERVER_ERROR; + } + + slot->ptr = entry->pool_used; + datastr = &entry->pool[slot->ptr]; + memcpy(datastr, string, str_len); + entry->pool_used += str_len; + return 0; +} + +/* Returns a pointer to the string in the storage slot specified + * + * + * Parametrs: + * am_cache_entry_t *entry Pointer to an entry + * am_cache_storage_t *slot Pointer to storage slot + * + * Returns: + * A string or NULL if the slot is empty. + */ +const char *am_cache_entry_get_string(am_cache_entry_t *e, + am_cache_storage_t *slot) +{ + char *ret = NULL; + + if (slot->ptr != 0) { + ret = &e->pool[slot->ptr]; + } + + return ret; +} /* This function locks the session table and creates a new session entry. * It will first attempt to locate a free session. If it doesn't find a @@ -227,6 +317,10 @@ am_cache_entry_t *am_cache_new(server_rec *s, const char *key) t->lasso_identity[0] = '\0'; t->lasso_session[0] = '\0'; + t->pool_size = am_cache_entry_pool_size(mod_cfg); + t->pool[0] = '\0'; + t->pool_used = 1; + return t; } diff --git a/auth_mellon_config.c b/auth_mellon_config.c index 36f6b96..0de3f96 100644 --- a/auth_mellon_config.c +++ b/auth_mellon_config.c @@ -862,6 +862,15 @@ const command_rec auth_mellon_commands[] = { " restart the server before any changes to this directive will" " take effect. The default value is 100." ), + AP_INIT_TAKE1( + "MellonCacheEntrySize", + am_set_module_config_int_slot, + (void *)APR_OFFSETOF(am_mod_cfg_rec, entry_size), + RSRC_CONF, + "The maximum size for a single session entry. You must" + " restart the server before any changes to this directive will" + " take effect. The default value is 192KiB." + ), AP_INIT_TAKE1( "MellonLockFile", am_set_module_config_file_slot, @@ -1571,8 +1580,11 @@ void *auth_mellon_server_config(apr_pool_t *p, server_rec *s) mod->post_count = post_count; mod->post_size = post_size; + mod->entry_size = AM_CACHE_DEFAULT_ENTRY_SIZE; + mod->init_cache_size = 0; mod->init_lock_file = NULL; + mod->init_entry_size = 0; mod->cache = NULL; mod->lock = NULL; diff --git a/mod_auth_mellon.c b/mod_auth_mellon.c index 86949a4..fc34962 100644 --- a/mod_auth_mellon.c +++ b/mod_auth_mellon.c @@ -88,9 +88,13 @@ static int am_global_init(apr_pool_t *conf, apr_pool_t *log, */ mod->init_cache_size = mod->cache_size; mod->init_lock_file = apr_pstrdup(conf, mod->lock_file); + mod->init_entry_size = mod->entry_size; + if (mod->init_entry_size < AM_CACHE_MIN_ENTRY_SIZE) { + mod->init_entry_size = AM_CACHE_MIN_ENTRY_SIZE; + } /* find out the memory size of the cache */ - mem_size = sizeof(am_cache_entry_t) * mod->init_cache_size; + mem_size = mod->init_entry_size * mod->init_cache_size; /* Create the shared memory, exit if it fails. */ -- cgit