xref: /PHP-7.4/ext/session/mod_mm.c (revision 8bda799d)
19ece649fSJani Taskinen /*
249824ee8SSascha Schumann    +----------------------------------------------------------------------+
3d0cb7153SJohannes Schlüter    | PHP Version 7                                                        |
449824ee8SSascha Schumann    +----------------------------------------------------------------------+
50cf7de1cSZeev Suraski    | Copyright (c) The PHP Group                                          |
649824ee8SSascha Schumann    +----------------------------------------------------------------------+
75bd93221Sfoobar    | This source file is subject to version 3.01 of the PHP license,      |
849824ee8SSascha Schumann    | that is bundled with this package in the file LICENSE, and is        |
9f68c7ff2SJames Cox    | available through the world-wide-web at the following url:           |
105bd93221Sfoobar    | http://www.php.net/license/3_01.txt                                  |
1149824ee8SSascha Schumann    | If you did not receive a copy of the PHP license and are unable to   |
1249824ee8SSascha Schumann    | obtain it through the world-wide-web, please send a note to          |
1349824ee8SSascha Schumann    | license@php.net so we can mail you a copy immediately.               |
1449824ee8SSascha Schumann    +----------------------------------------------------------------------+
1590613d22SSebastian Bergmann    | Author: Sascha Schumann <sascha@schumann.cx>                         |
1649824ee8SSascha Schumann    +----------------------------------------------------------------------+
1749824ee8SSascha Schumann  */
1849824ee8SSascha Schumann 
1949824ee8SSascha Schumann #include "php.h"
2049824ee8SSascha Schumann 
2149824ee8SSascha Schumann #ifdef HAVE_LIBMM
2249824ee8SSascha Schumann 
2393cb4816SYasuo Ohgaki #include <unistd.h>
2449824ee8SSascha Schumann #include <mm.h>
2549824ee8SSascha Schumann #include <time.h>
2649824ee8SSascha Schumann #include <sys/stat.h>
2749824ee8SSascha Schumann #include <sys/types.h>
2849824ee8SSascha Schumann #include <fcntl.h>
2949824ee8SSascha Schumann 
30a61029b1SRouven Weßling #include "php_stdint.h"
3149824ee8SSascha Schumann #include "php_session.h"
3249824ee8SSascha Schumann #include "mod_mm.h"
33d9692f78SYasuo Ohgaki #include "SAPI.h"
3449824ee8SSascha Schumann 
35ef42a25bSSascha Schumann #ifdef ZTS
36ef42a25bSSascha Schumann # error mm is not thread-safe
37ef42a25bSSascha Schumann #endif
38ef42a25bSSascha Schumann 
39d9692f78SYasuo Ohgaki #define PS_MM_FILE "session_mm_"
405b293ecdSSascha Schumann 
419ece649fSJani Taskinen /* This list holds all data associated with one session. */
425b293ecdSSascha Schumann 
4349824ee8SSascha Schumann typedef struct ps_sd {
44664df24dSSascha Schumann 	struct ps_sd *next;
45a61029b1SRouven Weßling 	uint32_t hv;		/* hash value of key */
46664df24dSSascha Schumann 	time_t ctime;		/* time of last change */
4749824ee8SSascha Schumann 	void *data;
48664df24dSSascha Schumann 	size_t datalen;		/* amount of valid data */
49664df24dSSascha Schumann 	size_t alloclen;	/* amount of allocated memory for data */
50ef42a25bSSascha Schumann 	char key[1];		/* inline key */
5149824ee8SSascha Schumann } ps_sd;
5249824ee8SSascha Schumann 
5349824ee8SSascha Schumann typedef struct {
5449824ee8SSascha Schumann 	MM *mm;
5549824ee8SSascha Schumann 	ps_sd **hash;
56a61029b1SRouven Weßling 	uint32_t hash_max;
57a61029b1SRouven Weßling 	uint32_t hash_cnt;
58ef42a25bSSascha Schumann 	pid_t owner;
5949824ee8SSascha Schumann } ps_mm;
6049824ee8SSascha Schumann 
6149824ee8SSascha Schumann static ps_mm *ps_mm_instance = NULL;
6249824ee8SSascha Schumann 
6349824ee8SSascha Schumann #if 0
649ece649fSJani Taskinen # define ps_mm_debug(a) printf a
6549824ee8SSascha Schumann #else
669ece649fSJani Taskinen # define ps_mm_debug(a)
6749824ee8SSascha Schumann #endif
6849824ee8SSascha Schumann 
ps_sd_hash(const char * data,int len)69a61029b1SRouven Weßling static inline uint32_t ps_sd_hash(const char *data, int len)
7049824ee8SSascha Schumann {
71a61029b1SRouven Weßling 	uint32_t h;
72ef42a25bSSascha Schumann 	const char *e = data + len;
739ece649fSJani Taskinen 
74ef42a25bSSascha Schumann 	for (h = 2166136261U; data < e; ) {
75eef0dda4SSascha Schumann 		h *= 16777619;
76ef42a25bSSascha Schumann 		h ^= *data++;
7749824ee8SSascha Schumann 	}
789ece649fSJani Taskinen 
79eef0dda4SSascha Schumann 	return h;
8049824ee8SSascha Schumann }
81ef42a25bSSascha Schumann 
hash_split(ps_mm * data)82ef42a25bSSascha Schumann static void hash_split(ps_mm *data)
83ef42a25bSSascha Schumann {
84a61029b1SRouven Weßling 	uint32_t nmax;
85ef42a25bSSascha Schumann 	ps_sd **nhash;
86ef42a25bSSascha Schumann 	ps_sd **ohash, **ehash;
87ef42a25bSSascha Schumann 	ps_sd *ps, *next;
889ece649fSJani Taskinen 
89ef42a25bSSascha Schumann 	nmax = ((data->hash_max + 1) << 1) - 1;
90ef42a25bSSascha Schumann 	nhash = mm_calloc(data->mm, nmax + 1, sizeof(*data->hash));
919ece649fSJani Taskinen 
92ef42a25bSSascha Schumann 	if (!nhash) {
93ef42a25bSSascha Schumann 		/* no further memory to expand hash table */
94ef42a25bSSascha Schumann 		return;
95ef42a25bSSascha Schumann 	}
96ef42a25bSSascha Schumann 
97ef42a25bSSascha Schumann 	ehash = data->hash + data->hash_max + 1;
98ef42a25bSSascha Schumann 	for (ohash = data->hash; ohash < ehash; ohash++) {
99ef42a25bSSascha Schumann 		for (ps = *ohash; ps; ps = next) {
100ef42a25bSSascha Schumann 			next = ps->next;
101ef42a25bSSascha Schumann 			ps->next = nhash[ps->hv & nmax];
102ef42a25bSSascha Schumann 			nhash[ps->hv & nmax] = ps;
103ef42a25bSSascha Schumann 		}
104ef42a25bSSascha Schumann 	}
105ef42a25bSSascha Schumann 	mm_free(data->mm, data->hash);
10649824ee8SSascha Schumann 
107ef42a25bSSascha Schumann 	data->hash = nhash;
108ef42a25bSSascha Schumann 	data->hash_max = nmax;
109ef42a25bSSascha Schumann }
110ef42a25bSSascha Schumann 
ps_sd_new(ps_mm * data,const char * key)111ef42a25bSSascha Schumann static ps_sd *ps_sd_new(ps_mm *data, const char *key)
11249824ee8SSascha Schumann {
113a61029b1SRouven Weßling 	uint32_t hv, slot;
11449824ee8SSascha Schumann 	ps_sd *sd;
115ef42a25bSSascha Schumann 	int keylen;
1169ece649fSJani Taskinen 
117ef42a25bSSascha Schumann 	keylen = strlen(key);
1189ece649fSJani Taskinen 
119ef42a25bSSascha Schumann 	sd = mm_malloc(data->mm, sizeof(ps_sd) + keylen);
120ef42a25bSSascha Schumann 	if (!sd) {
121b7a7b1a6SStanislav Malyshev 
122bdeb220fSAnatol Belski 		php_error_docref(NULL, E_WARNING, "mm_malloc failed, avail %ld, err %s", mm_available(data->mm), mm_error());
1235b293ecdSSascha Schumann 		return NULL;
1245b293ecdSSascha Schumann 	}
1255b293ecdSSascha Schumann 
126ef42a25bSSascha Schumann 	hv = ps_sd_hash(key, keylen);
127ef42a25bSSascha Schumann 	slot = hv & data->hash_max;
1289ece649fSJani Taskinen 
129ef42a25bSSascha Schumann 	sd->ctime = 0;
130ef42a25bSSascha Schumann 	sd->hv = hv;
131ef42a25bSSascha Schumann 	sd->data = NULL;
132ef42a25bSSascha Schumann 	sd->alloclen = sd->datalen = 0;
1339ece649fSJani Taskinen 
134ef42a25bSSascha Schumann 	memcpy(sd->key, key, keylen + 1);
1359ece649fSJani Taskinen 
136664df24dSSascha Schumann 	sd->next = data->hash[slot];
137664df24dSSascha Schumann 	data->hash[slot] = sd;
138ef42a25bSSascha Schumann 
139ef42a25bSSascha Schumann 	data->hash_cnt++;
1409ece649fSJani Taskinen 
141ef42a25bSSascha Schumann 	if (!sd->next) {
1429ece649fSJani Taskinen 		if (data->hash_cnt >= data->hash_max) {
143ef42a25bSSascha Schumann 			hash_split(data);
1449ece649fSJani Taskinen 		}
145ef42a25bSSascha Schumann 	}
1469ece649fSJani Taskinen 
147664df24dSSascha Schumann 	ps_mm_debug(("inserting %s(%p) into slot %d\n", key, sd, slot));
14849824ee8SSascha Schumann 
14949824ee8SSascha Schumann 	return sd;
15049824ee8SSascha Schumann }
15149824ee8SSascha Schumann 
ps_sd_destroy(ps_mm * data,ps_sd * sd)15249824ee8SSascha Schumann static void ps_sd_destroy(ps_mm *data, ps_sd *sd)
15349824ee8SSascha Schumann {
154a61029b1SRouven Weßling 	uint32_t slot;
15549824ee8SSascha Schumann 
156ef42a25bSSascha Schumann 	slot = ps_sd_hash(sd->key, strlen(sd->key)) & data->hash_max;
157664df24dSSascha Schumann 
1589ece649fSJani Taskinen 	if (data->hash[slot] == sd) {
159664df24dSSascha Schumann 		data->hash[slot] = sd->next;
1609ece649fSJani Taskinen 	} else {
161664df24dSSascha Schumann 		ps_sd *prev;
162664df24dSSascha Schumann 
163664df24dSSascha Schumann 		/* There must be some entry before the one we want to delete */
164664df24dSSascha Schumann 		for (prev = data->hash[slot]; prev->next != sd; prev = prev->next);
165664df24dSSascha Schumann 		prev->next = sd->next;
166664df24dSSascha Schumann 	}
1679ece649fSJani Taskinen 
168ef42a25bSSascha Schumann 	data->hash_cnt--;
1699ece649fSJani Taskinen 
1709ece649fSJani Taskinen 	if (sd->data) {
17112d3e3d7SSascha Schumann 		mm_free(data->mm, sd->data);
1729ece649fSJani Taskinen 	}
1739ece649fSJani Taskinen 
17449824ee8SSascha Schumann 	mm_free(data->mm, sd);
17549824ee8SSascha Schumann }
17649824ee8SSascha Schumann 
ps_sd_lookup(ps_mm * data,const char * key,int rw)17749824ee8SSascha Schumann static ps_sd *ps_sd_lookup(ps_mm *data, const char *key, int rw)
17849824ee8SSascha Schumann {
179a61029b1SRouven Weßling 	uint32_t hv, slot;
180ef42a25bSSascha Schumann 	ps_sd *ret, *prev;
18149824ee8SSascha Schumann 
182ef42a25bSSascha Schumann 	hv = ps_sd_hash(key, strlen(key));
183ef42a25bSSascha Schumann 	slot = hv & data->hash_max;
1849ece649fSJani Taskinen 
1859ece649fSJani Taskinen 	for (prev = NULL, ret = data->hash[slot]; ret; prev = ret, ret = ret->next) {
1869ece649fSJani Taskinen 		if (ret->hv == hv && !strcmp(ret->key, key)) {
18712d3e3d7SSascha Schumann 			break;
1889ece649fSJani Taskinen 		}
1899ece649fSJani Taskinen 	}
1909ece649fSJani Taskinen 
191664df24dSSascha Schumann 	if (ret && rw && ret != data->hash[slot]) {
192664df24dSSascha Schumann 		/* Move the entry to the top of the linked list */
1939ece649fSJani Taskinen 		if (prev) {
194ef42a25bSSascha Schumann 			prev->next = ret->next;
1959ece649fSJani Taskinen 		}
1969ece649fSJani Taskinen 
197664df24dSSascha Schumann 		ret->next = data->hash[slot];
198664df24dSSascha Schumann 		data->hash[slot] = ret;
19949824ee8SSascha Schumann 	}
20049824ee8SSascha Schumann 
201664df24dSSascha Schumann 	ps_mm_debug(("lookup(%s): ret=%p,hv=%u,slot=%d\n", key, ret, hv, slot));
2029ece649fSJani Taskinen 
20349824ee8SSascha Schumann 	return ret;
20449824ee8SSascha Schumann }
20549824ee8SSascha Schumann 
ps_mm_key_exists(ps_mm * data,const char * key)206bdeb220fSAnatol Belski static int ps_mm_key_exists(ps_mm *data, const char *key)
20725e8fcc8SYasuo Ohgaki {
20825e8fcc8SYasuo Ohgaki 	ps_sd *sd;
20925e8fcc8SYasuo Ohgaki 
21025e8fcc8SYasuo Ohgaki 	if (!key) {
21125e8fcc8SYasuo Ohgaki 		return FAILURE;
21225e8fcc8SYasuo Ohgaki 	}
21325e8fcc8SYasuo Ohgaki 	sd = ps_sd_lookup(data, key, 0);
21425e8fcc8SYasuo Ohgaki 	if (sd) {
21525e8fcc8SYasuo Ohgaki 		return SUCCESS;
21625e8fcc8SYasuo Ohgaki 	}
21725e8fcc8SYasuo Ohgaki 	return FAILURE;
21825e8fcc8SYasuo Ohgaki }
21925e8fcc8SYasuo Ohgaki 
22083e495e0SDmitry Stogov const ps_module ps_mod_mm = {
22125e8fcc8SYasuo Ohgaki 	PS_MOD_SID(mm)
22249824ee8SSascha Schumann };
22349824ee8SSascha Schumann 
22449824ee8SSascha Schumann #define PS_MM_DATA ps_mm *data = PS_GET_MOD_DATA()
22549824ee8SSascha Schumann 
ps_mm_initialize(ps_mm * data,const char * path)22649824ee8SSascha Schumann static int ps_mm_initialize(ps_mm *data, const char *path)
22749824ee8SSascha Schumann {
228ef42a25bSSascha Schumann 	data->owner = getpid();
22949824ee8SSascha Schumann 	data->mm = mm_create(0, path);
2300feb2a21SSascha Schumann 	if (!data->mm) {
2310feb2a21SSascha Schumann 		return FAILURE;
2320feb2a21SSascha Schumann 	}
23349824ee8SSascha Schumann 
234ef42a25bSSascha Schumann 	data->hash_cnt = 0;
235ef42a25bSSascha Schumann 	data->hash_max = 511;
236ef42a25bSSascha Schumann 	data->hash = mm_calloc(data->mm, data->hash_max + 1, sizeof(ps_sd *));
2370feb2a21SSascha Schumann 	if (!data->hash) {
2380feb2a21SSascha Schumann 		mm_destroy(data->mm);
2390feb2a21SSascha Schumann 		return FAILURE;
2400feb2a21SSascha Schumann 	}
24149824ee8SSascha Schumann 
24249824ee8SSascha Schumann 	return SUCCESS;
24349824ee8SSascha Schumann }
24449824ee8SSascha Schumann 
ps_mm_destroy(ps_mm * data)24549824ee8SSascha Schumann static void ps_mm_destroy(ps_mm *data)
24649824ee8SSascha Schumann {
2475b293ecdSSascha Schumann 	int h;
2485b293ecdSSascha Schumann 	ps_sd *sd, *next;
2495b293ecdSSascha Schumann 
250ef42a25bSSascha Schumann 	/* This function is called during each module shutdown,
251ef42a25bSSascha Schumann 	   but we must not release the shared memory pool, when
252ef42a25bSSascha Schumann 	   an Apache child dies! */
2539ece649fSJani Taskinen 	if (data->owner != getpid()) {
2549ece649fSJani Taskinen 		return;
2559ece649fSJani Taskinen 	}
256ef42a25bSSascha Schumann 
2579ece649fSJani Taskinen 	for (h = 0; h < data->hash_max + 1; h++) {
25812d3e3d7SSascha Schumann 		for (sd = data->hash[h]; sd; sd = next) {
2595b293ecdSSascha Schumann 			next = sd->next;
2605b293ecdSSascha Schumann 			ps_sd_destroy(data, sd);
2615b293ecdSSascha Schumann 		}
2629ece649fSJani Taskinen 	}
2639ece649fSJani Taskinen 
26449824ee8SSascha Schumann 	mm_free(data->mm, data->hash);
26549824ee8SSascha Schumann 	mm_destroy(data->mm);
266ef42a25bSSascha Schumann 	free(data);
26749824ee8SSascha Schumann }
26849824ee8SSascha Schumann 
PHP_MINIT_FUNCTION(ps_mm)26914ac3d74SAndi Gutmans PHP_MINIT_FUNCTION(ps_mm)
27049824ee8SSascha Schumann {
2710c69739fSSascha Schumann 	int save_path_len = strlen(PS(save_path));
272d9692f78SYasuo Ohgaki 	int mod_name_len = strlen(sapi_module.name);
273c6402df3SIlia Alshanetsky 	int euid_len;
27493cb4816SYasuo Ohgaki 	char *ps_mm_path, euid[30];
275770c39feSSascha Schumann 	int ret;
2765c0dfdbdSYasuo Ohgaki 
2775b293ecdSSascha Schumann 	ps_mm_instance = calloc(sizeof(*ps_mm_instance), 1);
2789ece649fSJani Taskinen 	if (!ps_mm_instance) {
279ae3edadcSYasuo Ohgaki 		return FAILURE;
280c6402df3SIlia Alshanetsky 	}
2815c0dfdbdSYasuo Ohgaki 
282efad70c2SIlia Alshanetsky 	if (!(euid_len = slprintf(euid, sizeof(euid), "%d", geteuid()))) {
283982c1157SFelipe Pena 		free(ps_mm_instance);
284982c1157SFelipe Pena 		ps_mm_instance = NULL;
285ae3edadcSYasuo Ohgaki 		return FAILURE;
286c6402df3SIlia Alshanetsky 	}
2879ece649fSJani Taskinen 
2889ece649fSJani Taskinen 	/* Directory + '/' + File + Module Name + Effective UID + \0 */
289c6402df3SIlia Alshanetsky 	ps_mm_path = emalloc(save_path_len + 1 + (sizeof(PS_MM_FILE) - 1) + mod_name_len + euid_len + 1);
2909ece649fSJani Taskinen 
291c6402df3SIlia Alshanetsky 	memcpy(ps_mm_path, PS(save_path), save_path_len);
292d3b20b40SFelipe Pena 	if (save_path_len && PS(save_path)[save_path_len - 1] != DEFAULT_SLASH) {
2930c69739fSSascha Schumann 		ps_mm_path[save_path_len] = DEFAULT_SLASH;
294c6402df3SIlia Alshanetsky 		save_path_len++;
2950c69739fSSascha Schumann 	}
296c667c70bSAntony Dovgal 	memcpy(ps_mm_path + save_path_len, PS_MM_FILE, sizeof(PS_MM_FILE) - 1);
297c6402df3SIlia Alshanetsky 	save_path_len += sizeof(PS_MM_FILE) - 1;
298c6402df3SIlia Alshanetsky 	memcpy(ps_mm_path + save_path_len, sapi_module.name, mod_name_len);
299c6402df3SIlia Alshanetsky 	save_path_len += mod_name_len;
300c6402df3SIlia Alshanetsky 	memcpy(ps_mm_path + save_path_len, euid, euid_len);
301c6402df3SIlia Alshanetsky 	ps_mm_path[save_path_len + euid_len] = '\0';
302c6402df3SIlia Alshanetsky 
303770c39feSSascha Schumann 	ret = ps_mm_initialize(ps_mm_instance, ps_mm_path);
3049ece649fSJani Taskinen 
305690ca62dSIlia Alshanetsky 	efree(ps_mm_path);
3069ece649fSJani Taskinen 
307770c39feSSascha Schumann 	if (ret != SUCCESS) {
308770c39feSSascha Schumann 		free(ps_mm_instance);
3090feb2a21SSascha Schumann 		ps_mm_instance = NULL;
310ae3edadcSYasuo Ohgaki 		return FAILURE;
3110feb2a21SSascha Schumann 	}
3129ece649fSJani Taskinen 
3139de9b7c1SSascha Schumann 	php_session_register_module(&ps_mod_mm);
3145b293ecdSSascha Schumann 	return SUCCESS;
3155b293ecdSSascha Schumann }
3165b293ecdSSascha Schumann 
3185b293ecdSSascha Schumann {
3190feb2a21SSascha Schumann 	if (ps_mm_instance) {
3200feb2a21SSascha Schumann 		ps_mm_destroy(ps_mm_instance);
3210feb2a21SSascha Schumann 		return SUCCESS;
3220feb2a21SSascha Schumann 	}
3230feb2a21SSascha Schumann 	return FAILURE;
3245b293ecdSSascha Schumann }
32549824ee8SSascha Schumann 
PS_OPEN_FUNC(mm)3265b293ecdSSascha Schumann PS_OPEN_FUNC(mm)
3275b293ecdSSascha Schumann {
328664df24dSSascha Schumann 	ps_mm_debug(("open: ps_mm_instance=%p\n", ps_mm_instance));
3299ece649fSJani Taskinen 
3309ece649fSJani Taskinen 	if (!ps_mm_instance) {
3317796f4d9SSascha Schumann 		return FAILURE;
3329ece649fSJani Taskinen 	}
33349824ee8SSascha Schumann 	PS_SET_MOD_DATA(ps_mm_instance);
3349ece649fSJani Taskinen 
33549824ee8SSascha Schumann 	return SUCCESS;
33649824ee8SSascha Schumann }
33749824ee8SSascha Schumann 
PS_CLOSE_FUNC(mm)33849824ee8SSascha Schumann PS_CLOSE_FUNC(mm)
33949824ee8SSascha Schumann {
34049824ee8SSascha Schumann 	PS_SET_MOD_DATA(NULL);
34149824ee8SSascha Schumann 
34249824ee8SSascha Schumann 	return SUCCESS;
34349824ee8SSascha Schumann }
34449824ee8SSascha Schumann 
PS_READ_FUNC(mm)34549824ee8SSascha Schumann PS_READ_FUNC(mm)
34649824ee8SSascha Schumann {
34749824ee8SSascha Schumann 	PS_MM_DATA;
34849824ee8SSascha Schumann 	ps_sd *sd;
34949824ee8SSascha Schumann 	int ret = FAILURE;
35049824ee8SSascha Schumann 
35149824ee8SSascha Schumann 	mm_lock(data->mm, MM_LOCK_RD);
3529ece649fSJani Taskinen 
35325e8fcc8SYasuo Ohgaki 	/* If there is an ID and strict mode, verify existence */
35425e8fcc8SYasuo Ohgaki 	if (PS(use_strict_mode)
355f1981365SXinchen Hui 		&& ps_mm_key_exists(data, key->val) == FAILURE) {
35625e8fcc8SYasuo Ohgaki 		/* key points to PS(id), but cannot change here. */
35725e8fcc8SYasuo Ohgaki 		if (key) {
35825e8fcc8SYasuo Ohgaki 			efree(PS(id));
35925e8fcc8SYasuo Ohgaki 			PS(id) = NULL;
36025e8fcc8SYasuo Ohgaki 		}
361f1981365SXinchen Hui 		PS(id) = PS(mod)->s_create_sid((void **)&data);
36225e8fcc8SYasuo Ohgaki 		if (!PS(id)) {
36325e8fcc8SYasuo Ohgaki 			return FAILURE;
36425e8fcc8SYasuo Ohgaki 		}
36525e8fcc8SYasuo Ohgaki 		if (PS(use_cookies)) {
36625e8fcc8SYasuo Ohgaki 			PS(send_cookie) = 1;
36725e8fcc8SYasuo Ohgaki 		}
368bdeb220fSAnatol Belski 		php_session_reset_id();
369f52c251fSYasuo Ohgaki 		PS(session_status) = php_session_active;
37025e8fcc8SYasuo Ohgaki 	}
37125e8fcc8SYasuo Ohgaki 
372f1981365SXinchen Hui 	sd = ps_sd_lookup(data, PS(id)->val, 0);
37312d3e3d7SSascha Schumann 	if (sd) {
374f1981365SXinchen Hui 		*val = zend_string_init(sd->data, sd->datalen, 0);
37549824ee8SSascha Schumann 		ret = SUCCESS;
37649824ee8SSascha Schumann 	}
377ca59cb7cSSascha Schumann 
37849824ee8SSascha Schumann 	mm_unlock(data->mm);
3799ece649fSJani Taskinen 
38049824ee8SSascha Schumann 	return ret;
38149824ee8SSascha Schumann }
38249824ee8SSascha Schumann 
PS_WRITE_FUNC(mm)38349824ee8SSascha Schumann PS_WRITE_FUNC(mm)
38449824ee8SSascha Schumann {
38549824ee8SSascha Schumann 	PS_MM_DATA;
38649824ee8SSascha Schumann 	ps_sd *sd;
38749824ee8SSascha Schumann 
38849824ee8SSascha Schumann 	mm_lock(data->mm, MM_LOCK_RW);
38949824ee8SSascha Schumann 
390f1981365SXinchen Hui 	sd = ps_sd_lookup(data, key->val, 1);
39112d3e3d7SSascha Schumann 	if (!sd) {
392f1981365SXinchen Hui 		sd = ps_sd_new(data, key->val);
393f1981365SXinchen Hui 		ps_mm_debug(("new entry for %s\n", key->val));
394ef42a25bSSascha Schumann 	}
395664df24dSSascha Schumann 
396ef42a25bSSascha Schumann 	if (sd) {
397f1981365SXinchen Hui 		if (val->len >= sd->alloclen) {
3989ece649fSJani Taskinen 			if (data->mm) {
399ef42a25bSSascha Schumann 				mm_free(data->mm, sd->data);
4009ece649fSJani Taskinen 			}
401f1981365SXinchen Hui 			sd->alloclen = val->len + 1;
402664df24dSSascha Schumann 			sd->data = mm_malloc(data->mm, sd->alloclen);
403664df24dSSascha Schumann 
404664df24dSSascha Schumann 			if (!sd->data) {
405664df24dSSascha Schumann 				ps_sd_destroy(data, sd);
406bdeb220fSAnatol Belski 				php_error_docref(NULL, E_WARNING, "cannot allocate new data segment");
407664df24dSSascha Schumann 				sd = NULL;
408664df24dSSascha Schumann 			}
409664df24dSSascha Schumann 		}
410664df24dSSascha Schumann 		if (sd) {
411f1981365SXinchen Hui 			sd->datalen = val->len;
412f1981365SXinchen Hui 			memcpy(sd->data, val->val, val->len);
413ef42a25bSSascha Schumann 			time(&sd->ctime);
414664df24dSSascha Schumann 		}
41549824ee8SSascha Schumann 	}
41649824ee8SSascha Schumann 
41749824ee8SSascha Schumann 	mm_unlock(data->mm);
4189ece649fSJani Taskinen 
4195b293ecdSSascha Schumann 	return sd ? SUCCESS : FAILURE;
42049824ee8SSascha Schumann }
42149824ee8SSascha Schumann 
PS_DESTROY_FUNC(mm)42249824ee8SSascha Schumann PS_DESTROY_FUNC(mm)
42349824ee8SSascha Schumann {
42449824ee8SSascha Schumann 	PS_MM_DATA;
42549824ee8SSascha Schumann 	ps_sd *sd;
4269ece649fSJani Taskinen 
42749824ee8SSascha Schumann 	mm_lock(data->mm, MM_LOCK_RW);
4289ece649fSJani Taskinen 
429f1981365SXinchen Hui 	sd = ps_sd_lookup(data, key->val, 0);
4309ece649fSJani Taskinen 	if (sd) {
43149824ee8SSascha Schumann 		ps_sd_destroy(data, sd);
4329ece649fSJani Taskinen 	}
4339ece649fSJani Taskinen 
43449824ee8SSascha Schumann 	mm_unlock(data->mm);
4359ece649fSJani Taskinen 
43649824ee8SSascha Schumann 	return SUCCESS;
43749824ee8SSascha Schumann }
43849824ee8SSascha Schumann 
PS_GC_FUNC(mm)4399ece649fSJani Taskinen PS_GC_FUNC(mm)
44049824ee8SSascha Schumann {
44149824ee8SSascha Schumann 	PS_MM_DATA;
442664df24dSSascha Schumann 	time_t limit;
443ef42a25bSSascha Schumann 	ps_sd **ohash, **ehash;
44449824ee8SSascha Schumann 	ps_sd *sd, *next;
4459ece649fSJani Taskinen 
446f50de703SSascha Schumann 	*nrdels = 0;
447664df24dSSascha Schumann 	ps_mm_debug(("gc\n"));
4489ece649fSJani Taskinen 
449664df24dSSascha Schumann 	time(&limit);
450664df24dSSascha Schumann 
451664df24dSSascha Schumann 	limit -= maxlifetime;
452664df24dSSascha Schumann 
45349824ee8SSascha Schumann 	mm_lock(data->mm, MM_LOCK_RW);
45449824ee8SSascha Schumann 
455ef42a25bSSascha Schumann 	ehash = data->hash + data->hash_max + 1;
4569ece649fSJani Taskinen 	for (ohash = data->hash; ohash < ehash; ohash++) {
457ef42a25bSSascha Schumann 		for (sd = *ohash; sd; sd = next) {
45849824ee8SSascha Schumann 			next = sd->next;
459664df24dSSascha Schumann 			if (sd->ctime < limit) {
460664df24dSSascha Schumann 				ps_mm_debug(("purging %s\n", sd->key));
46149824ee8SSascha Schumann 				ps_sd_destroy(data, sd);
462664df24dSSascha Schumann 				(*nrdels)++;
463f50de703SSascha Schumann 			}
46449824ee8SSascha Schumann 		}
4659ece649fSJani Taskinen 	}
46649824ee8SSascha Schumann 
46749824ee8SSascha Schumann 	mm_unlock(data->mm);
4689ece649fSJani Taskinen 
469*8bda799dSNikita Popov 	return *nrdels;
47049824ee8SSascha Schumann }
47149824ee8SSascha Schumann 
PS_CREATE_SID_FUNC(mm)47225e8fcc8SYasuo Ohgaki PS_CREATE_SID_FUNC(mm)
47325e8fcc8SYasuo Ohgaki {
474f1981365SXinchen Hui 	zend_string *sid;
47582b0e8beSYasuo Ohgaki 	int maxfail = 3;
47625e8fcc8SYasuo Ohgaki 	PS_MM_DATA;
47725e8fcc8SYasuo Ohgaki 
47882b0e8beSYasuo Ohgaki 	do {
479f1981365SXinchen Hui 		sid = php_session_create_id((void **)&data);
48082b0e8beSYasuo Ohgaki 		/* Check collision */
481f1981365SXinchen Hui 		if (ps_mm_key_exists(data, sid->val) == SUCCESS) {
48282b0e8beSYasuo Ohgaki 			if (sid) {
4835eb1f92fSDmitry Stogov 				zend_string_release_ex(sid, 0);
48482b0e8beSYasuo Ohgaki 				sid = NULL;
48582b0e8beSYasuo Ohgaki 			}
48682b0e8beSYasuo Ohgaki 			if (!(maxfail--)) {
48782b0e8beSYasuo Ohgaki 				return NULL;
48882b0e8beSYasuo Ohgaki 			}
48982b0e8beSYasuo Ohgaki 		}
49082b0e8beSYasuo Ohgaki 	} while(!sid);
49125e8fcc8SYasuo Ohgaki 
49225e8fcc8SYasuo Ohgaki 	return sid;
49325e8fcc8SYasuo Ohgaki }
49425e8fcc8SYasuo Ohgaki 
49549824ee8SSascha Schumann #endif