summaryrefslogtreecommitdiff
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
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.
-rw-r--r--ext/session/Makefile.am2
-rw-r--r--ext/session/config.h.stub3
-rw-r--r--ext/session/config.m425
-rw-r--r--ext/session/mod_files.c4
-rw-r--r--ext/session/mod_mm.c277
-rw-r--r--ext/session/mod_mm.h46
-rw-r--r--ext/session/modules.c3
-rw-r--r--ext/session/php_session.h2
-rw-r--r--ext/session/session.c19
9 files changed, 369 insertions, 12 deletions
diff --git a/ext/session/Makefile.am b/ext/session/Makefile.am
index bb35d2e5b9..b1a8250d50 100644
--- a/ext/session/Makefile.am
+++ b/ext/session/Makefile.am
@@ -2,5 +2,5 @@
INCLUDES=@INCLUDES@ -I@top_srcdir@ -I@top_srcdir@/libzend
noinst_LIBRARIES=libphpext_session.a
-libphpext_session_a_SOURCES=session.c mod_files.c
+libphpext_session_a_SOURCES=session.c mod_files.c mod_mm.c
diff --git a/ext/session/config.h.stub b/ext/session/config.h.stub
index bce855c110..4dc5ec115c 100644
--- a/ext/session/config.h.stub
+++ b/ext/session/config.h.stub
@@ -1,2 +1,3 @@
/* define if you want to use the session extension */
-/* #undef HAVE_LIBSESSION */
+
+#undef HAVE_LIBMM
diff --git a/ext/session/config.m4 b/ext/session/config.m4
index 30b8226bd3..a85c321f24 100644
--- a/ext/session/config.m4
+++ b/ext/session/config.m4
@@ -2,4 +2,29 @@ dnl $Id$
dnl config.m4 for extension session
dnl don't forget to call PHP_EXTENSION(session)
+
+MM_RESULT=no
+AC_MSG_CHECKING(for mm support)
+AC_ARG_WITH(mm,
+[ --with-mm[=DIR] Include mm support],
+[
+ if test "$withval" != "no"; then
+ for i in /usr/local /usr $withval; do
+ if test -f "$i/include/mm.h"; then
+ MM_DIR="$i"
+ fi
+ done
+
+ if test -z "$MM_DIR" ; then
+ AC_MSG_ERROR(cannot find mm library)
+ fi
+
+ AC_ADD_LIBRARY_WITH_PATH(mm, $MM_DIR/lib)
+ AC_ADD_INCLUDE($MM_DIR/include)
+ AC_DEFINE(HAVE_LIBMM, 1)
+ MM_RESULT=yes
+ fi
+])
+AC_MSG_RESULT($MM_RESULT)
+
PHP_EXTENSION(session)
diff --git a/ext/session/mod_files.c b/ext/session/mod_files.c
index 77e6ccd5ec..32bd760f88 100644
--- a/ext/session/mod_files.c
+++ b/ext/session/mod_files.c
@@ -43,7 +43,7 @@ ps_module ps_mod_files = {
PS_MOD(files)
};
-#define PS_FILES_DATA ps_files *data = *mod_data
+#define PS_FILES_DATA ps_files *data = PS_GET_MOD_DATA()
PS_OPEN_FUNC(files)
{
@@ -51,7 +51,7 @@ PS_OPEN_FUNC(files)
char *p;
data = ecalloc(sizeof(*data), 1);
- *mod_data = data;
+ PS_SET_MOD_DATA(data);
data->fd = -1;
if((p = strchr(save_path, ':'))) {
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
diff --git a/ext/session/mod_mm.h b/ext/session/mod_mm.h
new file mode 100644
index 0000000000..e3cfe2db1f
--- /dev/null
+++ b/ext/session/mod_mm.h
@@ -0,0 +1,46 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP HTML Embedded Scripting Language Version 4.0 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997,1998 PHP Development Team (See Credits file) |
+ +----------------------------------------------------------------------+
+ | This program is free software; you can redistribute it and/or modify |
+ | it under the terms of one of the following licenses: |
+ | |
+ | A) the GNU General Public License as published by the Free Software |
+ | Foundation; either version 2 of the License, or (at your option) |
+ | any later version. |
+ | |
+ | B) the PHP License as published by the PHP Development Team and |
+ | included in the distribution in the file: LICENSE |
+ | |
+ | This program is distributed in the hope that it will be useful, |
+ | but WITHOUT ANY WARRANTY; without even the implied warranty of |
+ | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
+ | GNU General Public License for more details. |
+ | |
+ | You should have received a copy of both licenses referred to here. |
+ | If you did not, or have any questions about PHP licensing, please |
+ | contact core@php.net. |
+ +----------------------------------------------------------------------+
+ | Authors: Sascha Schumann <ss@2ns.de> |
+ +----------------------------------------------------------------------+
+ */
+
+#ifndef MOD_MM_H
+#define MOD_MM_H
+
+#ifdef HAVE_LIBMM
+
+extern ps_module ps_mod_mm;
+#define ps_mm_ptr &ps_mod_mm
+
+PS_FUNCS(mm);
+
+#else
+
+#define ps_mm_ptr NULL
+
+#endif
+
+#endif
diff --git a/ext/session/modules.c b/ext/session/modules.c
index 50d2062854..86613696bb 100644
--- a/ext/session/modules.c
+++ b/ext/session/modules.c
@@ -4,9 +4,10 @@
*/
#include "mod_files.h"
+#include "mod_mm.h"
static ps_module *ps_modules[] = {
ps_files_ptr,
- 0,
+ ps_mm_ptr,
};
diff --git a/ext/session/php_session.h b/ext/session/php_session.h
index 5964d69d82..c543f800d8 100644
--- a/ext/session/php_session.h
+++ b/ext/session/php_session.h
@@ -57,6 +57,8 @@ typedef struct ps_module_struct {
int (*gc)(PS_GC_ARGS);
} ps_module;
+#define PS_GET_MOD_DATA() *mod_data
+#define PS_SET_MOD_DATA(a) *mod_data = (a)
#define PS_OPEN_FUNC(x) int _ps_open_##x(PS_OPEN_ARGS)
#define PS_CLOSE_FUNC(x) int _ps_close_##x(PS_CLOSE_ARGS)
diff --git a/ext/session/session.c b/ext/session/session.c
index 272a27a467..7b4bb8988d 100644
--- a/ext/session/session.c
+++ b/ext/session/session.c
@@ -21,7 +21,6 @@
* TODO:
* - add complete support for objects (partially implemented)
* - userland callback functions for ps_module
- * - write ps_module utilizing shared memory (mm)
*/
#if !(WIN32|WINNT)
#include <sys/time.h>
@@ -279,9 +278,10 @@ static void _php_session_send_cookie(PSLS_D)
date_fmt = php3_std_date(time(NULL) + PS(lifetime));
len += sizeof(COOKIE_EXPIRES) + strlen(date_fmt);
}
- cookie = emalloc(len + 1);
+ cookie = ecalloc(len + 1, 1);
snprintf(cookie, len, COOKIE_FMT, PS(session_name), PS(id));
+ cookie[len] = '\0';
if (PS(lifetime) > 0) {
strcat(cookie, COOKIE_EXPIRES);
strcat(cookie, date_fmt);
@@ -295,8 +295,9 @@ static ps_module *_php_find_ps_module(char *name PSLS_DC)
{
ps_module *ret = NULL;
ps_module **mod;
+ ps_module **end = ps_modules + (sizeof(ps_modules)/sizeof(ps_module*));
- for(mod = ps_modules; ((*mod && (*mod)->name) || !*mod); mod++) {
+ for(mod = ps_modules; mod < end; mod++) {
if(*mod && !strcasecmp(name, (*mod)->name)) {
ret = *mod;
break;
@@ -333,7 +334,7 @@ static void _php_session_start(PSLS_D)
int lensess;
ELS_FETCH();
- if (PS(nr_open_sessions) > 0) return;
+ if (PS(nr_open_sessions) != 0) return;
lensess = strlen(PS(session_name));
@@ -419,7 +420,7 @@ static void _php_session_start(PSLS_D)
if(PS(mod_data) && PS(gc_probability) > 0) {
srand(time(NULL));
nrand = (int) (100.0*rand()/RAND_MAX);
- if(nrand >= PS(gc_probability))
+ if(nrand < PS(gc_probability))
PS(mod)->gc(&PS(mod_data), PS(gc_maxlifetime));
}
}
@@ -694,11 +695,15 @@ int php_rinit_session(INIT_FUNC_ARGS)
php_rinit_session_globals(PSLS_C);
+ if(PS(mod) == NULL) {
+ /* current status is unusable */
+ PS(nr_open_sessions) = -1;
+ return FAILURE;
+ }
+
if(INI_INT("session_auto_start")) {
_php_session_start(PSLS_C);
}
- if(PS(mod) == NULL)
- return FAILURE;
return SUCCESS;
}