summaryrefslogtreecommitdiff
path: root/ext/session/mod_mm.c
diff options
context:
space:
mode:
authorSascha Schumann <sas@php.net>1999-08-27 21:03:22 +0000
committerSascha Schumann <sas@php.net>1999-08-27 21:03:22 +0000
commit49824ee8cbcfcc9bc66e4a21db90cb9e63009650 (patch)
treee689be2de0dad0f57b61c0f1dfb711e9e539a4fe /ext/session/mod_mm.c
parentaa8b27ba1d6867e367416a02a6c47489dc3bbc76 (diff)
downloadphp-git-49824ee8cbcfcc9bc66e4a21db90cb9e63009650.tar.gz
- fix potential buffer problem in send_cookie
- fix gc probability algorithm - don't access mod_data directly - initial version of mm support for session data storage This works pretty good, but we need to create the initial mm pool from the parent process/thread. Still looking for a clean way to do that.
Diffstat (limited to 'ext/session/mod_mm.c')
-rw-r--r--ext/session/mod_mm.c277
1 files changed, 277 insertions, 0 deletions
diff --git a/ext/session/mod_mm.c b/ext/session/mod_mm.c
new file mode 100644
index 0000000000..5361dc38ff
--- /dev/null
+++ b/ext/session/mod_mm.c
@@ -0,0 +1,277 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP version 4.0 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997, 1998, 1999 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 2.0 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available at through the world-wide-web at |
+ | http://www.php.net/license/2_0.txt. |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Sascha Schumann <ss@2ns.de> |
+ +----------------------------------------------------------------------+
+ */
+
+
+#include "php.h"
+
+#ifdef HAVE_LIBMM
+
+#include <mm.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+#include "php_session.h"
+#include "mod_mm.h"
+
+typedef struct ps_sd {
+ time_t ctime;
+ char *key;
+ void *data;
+ size_t datalen;
+ struct ps_sd *next, *prev;
+} ps_sd;
+
+typedef struct {
+ MM *mm;
+ ps_sd **hash;
+} ps_mm;
+
+static ps_mm *ps_mm_instance = NULL;
+
+/* should be a prime */
+#define HASH_SIZE 11
+
+#if 0
+#define ps_mm_debug(a...) fprintf(stderr, a)
+#else
+#define ps_mm_debug(a...)
+#endif
+
+#define BITS_IN_int (sizeof(int) * CHAR_BIT)
+#define THREE_QUARTERS ((int) ((BITS_IN_int * 3) / 4))
+#define ONE_EIGTH ((int) (BITS_IN_int / 8))
+#define HIGH_BITS (~((unsigned int)(~0) >> ONE_EIGTH))
+
+static unsigned int ps_sd_hash(const char *data)
+{
+ unsigned int val, i;
+
+ for(val = 0; *data; data++) {
+ val = (val << ONE_EIGTH) + *data;
+ if((i = val & HIGH_BITS) != 0) {
+ val = (val ^ (i >> THREE_QUARTERS)) & -HIGH_BITS;
+ }
+ }
+
+ return val;
+}
+
+
+static ps_sd *ps_sd_new(ps_mm *data, const char *key, const void *sdata, size_t sdatalen)
+{
+ unsigned int h;
+ ps_sd *sd;
+
+ h = ps_sd_hash(key) % HASH_SIZE;
+
+ sd = mm_malloc(data->mm, sizeof(*sd));
+ sd->ctime = 0;
+
+ sd->data = mm_malloc(data->mm, sdatalen);
+ memcpy(sd->data, sdata, sdatalen);
+ sd->datalen = sdatalen;
+
+ sd->key = mm_strdup(data->mm, key);
+
+ if((sd->next = data->hash[h]))
+ sd->next->prev = sd;
+ sd->prev = NULL;
+
+ ps_mm_debug("inserting %s(%x) into %d\n", key, sd, h);
+
+ data->hash[h] = sd;
+
+ return sd;
+}
+
+static void ps_sd_destroy(ps_mm *data, ps_sd *sd)
+{
+ unsigned int h;
+
+ h = ps_sd_hash(sd->key) % HASH_SIZE;
+
+ if(sd->next)
+ sd->next->prev = sd->prev;
+ if(sd->prev)
+ sd->prev->next = sd->next;
+
+ if(data->hash[h] == sd)
+ data->hash[h] = sd->next;
+
+ mm_free(data->mm, sd->key);
+ mm_free(data->mm, sd->data);
+ mm_free(data->mm, sd);
+}
+
+static ps_sd *ps_sd_lookup(ps_mm *data, const char *key, int rw)
+{
+ unsigned int h;
+ ps_sd *ret;
+
+ h = ps_sd_hash(key) % HASH_SIZE;
+
+ for(ret = data->hash[h]; ret; ret = ret->next)
+ if(!strcmp(ret->key, key)) break;
+
+ if(ret && rw && ret != data->hash[h]) {
+ data->hash[h]->prev = ret;
+ ret->next = data->hash[h];
+ data->hash[h] = ret;
+ ps_mm_debug("optimizing\n");
+ }
+
+ ps_mm_debug(stderr, "lookup(%s): ret=%x,h=%d\n", key, ret, h);
+
+ return ret;
+}
+
+ps_module ps_mod_mm = {
+ PS_MOD(mm)
+};
+
+#define PS_MM_DATA ps_mm *data = PS_GET_MOD_DATA()
+
+static int ps_mm_initialize(ps_mm *data, const char *path)
+{
+ data->mm = mm_create(0, path);
+
+ data->hash = mm_calloc(data->mm, HASH_SIZE, sizeof(*data->hash));
+
+ return SUCCESS;
+}
+
+static void ps_mm_destroy(ps_mm *data)
+{
+ mm_free(data->mm, data->hash);
+ mm_destroy(data->mm);
+}
+
+PS_OPEN_FUNC(mm)
+{
+ if(!ps_mm_instance) {
+ ps_mm_instance = calloc(sizeof(*data), 1);
+ ps_mm_initialize(ps_mm_instance, save_path);
+ }
+
+ PS_SET_MOD_DATA(ps_mm_instance);
+
+ return SUCCESS;
+}
+
+PS_CLOSE_FUNC(mm)
+{
+ PS_SET_MOD_DATA(NULL);
+
+ return SUCCESS;
+}
+
+PS_READ_FUNC(mm)
+{
+ PS_MM_DATA;
+ ps_sd *sd;
+ int ret = FAILURE;
+
+ mm_lock(data->mm, MM_LOCK_RD);
+
+ sd = ps_sd_lookup(data, key, 0);
+ if(sd) {
+ *vallen = sd->datalen;
+ *val = emalloc(sd->datalen);
+ memcpy(*val, sd->data, sd->datalen);
+ ret = SUCCESS;
+ }
+
+ mm_unlock(data->mm);
+
+ return ret;
+}
+
+PS_WRITE_FUNC(mm)
+{
+ PS_MM_DATA;
+ ps_sd *sd;
+
+ mm_lock(data->mm, MM_LOCK_RW);
+
+ sd = ps_sd_lookup(data, key, 1);
+ if(!sd) {
+ sd = ps_sd_new(data, key, val, vallen);
+ ps_mm_debug(stderr, "new one for %s\n", key);
+ } else {
+ ps_mm_debug(stderr, "found existing one for %s\n", key);
+ mm_free(data->mm, sd->data);
+ sd->datalen = vallen;
+ sd->data = mm_malloc(data->mm, vallen);
+ memcpy(sd->data, val, vallen);
+ }
+
+ time(&sd->ctime);
+
+ mm_unlock(data->mm);
+
+ return SUCCESS;
+}
+
+PS_DESTROY_FUNC(mm)
+{
+ PS_MM_DATA;
+ ps_sd *sd;
+
+ mm_lock(data->mm, MM_LOCK_RW);
+
+ sd = ps_sd_lookup(data, key, 0);
+ if(sd) {
+ ps_sd_destroy(data, sd);
+ }
+
+ mm_unlock(data->mm);
+
+ return SUCCESS;
+}
+
+PS_GC_FUNC(mm)
+{
+ PS_MM_DATA;
+ int h;
+ time_t now;
+ ps_sd *sd, *next;
+
+ ps_mm_debug("gc\n");
+
+ mm_lock(data->mm, MM_LOCK_RW);
+
+ time(&now);
+
+ for(h = 0; h < HASH_SIZE; h++) {
+ for(sd = data->hash[h]; sd; sd = next) {
+ next = sd->next;
+ ps_mm_debug("looking at %s\n", sd->key);
+ if((now - sd->ctime) > maxlifetime) {
+ ps_sd_destroy(data, sd);
+ }
+ }
+ }
+
+ mm_unlock(data->mm);
+
+ return SUCCESS;
+}
+
+#endif