1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 5 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1997-2009 The PHP Group |
6 : +----------------------------------------------------------------------+
7 : | This source file is subject to version 3.01 of the PHP license, |
8 : | that is bundled with this package in the file LICENSE, and is |
9 : | available through the world-wide-web at the following url: |
10 : | http://www.php.net/license/3_01.txt |
11 : | If you did not receive a copy of the PHP license and are unable to |
12 : | obtain it through the world-wide-web, please send a note to |
13 : | license@php.net so we can mail you a copy immediately. |
14 : +----------------------------------------------------------------------+
15 : | Author: Christian Cartus <cartus@atrior.de> |
16 : +----------------------------------------------------------------------+
17 : */
18 :
19 : /* $Id: sysvshm.c 277495 2009-03-19 23:10:44Z iliaa $ */
20 :
21 : /* This has been built and tested on Linux 2.2.14
22 : *
23 : * This has been built and tested on Solaris 2.6.
24 : * It may not compile or execute correctly on other systems.
25 : */
26 :
27 : #ifdef HAVE_CONFIG_H
28 : #include "config.h"
29 : #endif
30 :
31 : #include "php.h"
32 :
33 : #if HAVE_SYSVSHM
34 :
35 : #include <errno.h>
36 :
37 : #include "php_sysvshm.h"
38 : #include "ext/standard/php_var.h"
39 : #include "ext/standard/php_smart_str.h"
40 : #include "php_ini.h"
41 :
42 : /* {{{ sysvshm_functions[]
43 : */
44 : zend_function_entry sysvshm_functions[] = {
45 : PHP_FE(shm_attach, NULL)
46 : PHP_FE(shm_remove, NULL)
47 : PHP_FE(shm_detach, NULL)
48 : PHP_FE(shm_put_var, NULL)
49 : PHP_FE(shm_get_var, NULL)
50 : PHP_FE(shm_remove_var, NULL)
51 : {NULL, NULL, NULL}
52 : };
53 : /* }}} */
54 :
55 : /* {{{ sysvshm_module_entry
56 : */
57 : zend_module_entry sysvshm_module_entry = {
58 : STANDARD_MODULE_HEADER,
59 : "sysvshm",
60 : sysvshm_functions,
61 : PHP_MINIT(sysvshm),
62 : NULL,
63 : NULL,
64 : NULL,
65 : NULL,
66 : NO_VERSION_YET,
67 : STANDARD_MODULE_PROPERTIES
68 : };
69 : /* }}} */
70 :
71 : #ifdef COMPILE_DL_SYSVSHM
72 : ZEND_GET_MODULE(sysvshm)
73 : #endif
74 :
75 : #undef shm_ptr /* undefine AIX-specific macro */
76 :
77 : THREAD_LS sysvshm_module php_sysvshm;
78 :
79 : static int php_put_shm_data(sysvshm_chunk_head *ptr, long key, char *data, long len);
80 : static long php_check_shm_data(sysvshm_chunk_head *ptr, long key);
81 : static int php_remove_shm_data(sysvshm_chunk_head *ptr, long shm_varpos);
82 :
83 : /* {{{ php_release_sysvshm
84 : */
85 : static void php_release_sysvshm(zend_rsrc_list_entry *rsrc TSRMLS_DC)
86 12 : {
87 12 : sysvshm_shm *shm_ptr = (sysvshm_shm *) rsrc->ptr;
88 12 : shmdt((void *) shm_ptr->ptr);
89 12 : efree(shm_ptr);
90 12 : }
91 : /* }}} */
92 :
93 : /* {{{ PHP_MINIT_FUNCTION
94 : */
95 : PHP_MINIT_FUNCTION(sysvshm)
96 13565 : {
97 13565 : php_sysvshm.le_shm = zend_register_list_destructors_ex(php_release_sysvshm, NULL, "sysvshm", module_number);
98 :
99 13565 : if (cfg_get_long("sysvshm.init_mem", &php_sysvshm.init_mem) == FAILURE) {
100 13565 : php_sysvshm.init_mem=10000;
101 : }
102 13565 : return SUCCESS;
103 : }
104 : /* }}} */
105 :
106 : /* {{{ proto int shm_attach(int key [, int memsize [, int perm]])
107 : Creates or open a shared memory segment */
108 : PHP_FUNCTION(shm_attach)
109 19 : {
110 : zval **arg_key, **arg_size, **arg_flag;
111 : long shm_size, shm_flag;
112 : sysvshm_shm *shm_list_ptr;
113 : char *shm_ptr;
114 : sysvshm_chunk_head *chunk_ptr;
115 19 : key_t shm_key = (key_t) 0;
116 : long shm_id, list_id;
117 19 : int ac = ZEND_NUM_ARGS();
118 :
119 19 : shm_flag = 0666;
120 19 : shm_size = php_sysvshm.init_mem;
121 :
122 19 : if (ac < 1 || ac > 3 || zend_get_parameters_ex(ac, &arg_key, &arg_size, &arg_flag) == FAILURE) {
123 2 : WRONG_PARAM_COUNT;
124 : }
125 :
126 17 : switch (ac) {
127 : case 3:
128 1 : convert_to_long_ex(arg_flag);
129 1 : shm_flag = Z_LVAL_PP(arg_flag);
130 : case 2:
131 14 : convert_to_long_ex(arg_size);
132 14 : shm_size= Z_LVAL_PP(arg_size);
133 : case 1:
134 17 : convert_to_long_ex(arg_key);
135 17 : shm_key = Z_LVAL_PP(arg_key);
136 : }
137 :
138 17 : if (shm_size < 1) {
139 5 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Segment size must be greater then zero.");
140 5 : RETURN_FALSE;
141 : }
142 :
143 12 : shm_list_ptr = (sysvshm_shm *) emalloc(sizeof(sysvshm_shm));
144 :
145 : /* get the id from a specified key or create new shared memory */
146 12 : if ((shm_id = shmget(shm_key, 0, 0)) < 0) {
147 9 : if (shm_size < sizeof(sysvshm_chunk_head)) {
148 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed for key 0x%x: memorysize too small", shm_key);
149 0 : efree(shm_list_ptr);
150 0 : RETURN_FALSE;
151 : }
152 9 : if ((shm_id = shmget(shm_key, shm_size, shm_flag | IPC_CREAT | IPC_EXCL)) < 0) {
153 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed for key 0x%x: %s", shm_key, strerror(errno));
154 0 : efree(shm_list_ptr);
155 0 : RETURN_FALSE;
156 : }
157 : }
158 :
159 12 : if ((shm_ptr = shmat(shm_id, NULL, 0)) == (void *) - 1) {
160 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed for key 0x%x: %s", shm_key, strerror(errno));
161 0 : efree(shm_list_ptr);
162 0 : RETURN_FALSE;
163 : }
164 :
165 : /* check if shm is already initialized */
166 12 : chunk_ptr = (sysvshm_chunk_head *) shm_ptr;
167 12 : if (strcmp((char*) &(chunk_ptr->magic), "PHP_SM") != 0) {
168 9 : strcpy((char*) &(chunk_ptr->magic), "PHP_SM");
169 9 : chunk_ptr->start = sizeof(sysvshm_chunk_head);
170 9 : chunk_ptr->end = chunk_ptr->start;
171 9 : chunk_ptr->total = shm_size;
172 9 : chunk_ptr->free = shm_size-chunk_ptr->end;
173 : }
174 :
175 12 : shm_list_ptr->key = shm_key;
176 12 : shm_list_ptr->id = shm_id;
177 12 : shm_list_ptr->ptr = chunk_ptr;
178 12 : list_id = zend_list_insert(shm_list_ptr, php_sysvshm.le_shm);
179 12 : RETURN_LONG(list_id);
180 : }
181 : /* }}} */
182 :
183 : /* {{{ proto bool shm_detach(int shm_identifier)
184 : Disconnects from shared memory segment */
185 : PHP_FUNCTION(shm_detach)
186 8 : {
187 : zval **arg_id;
188 : int type;
189 : sysvshm_shm *shm_list_ptr;
190 :
191 8 : if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &arg_id) == FAILURE) {
192 2 : WRONG_PARAM_COUNT;
193 : }
194 :
195 6 : convert_to_long_ex(arg_id);
196 6 : shm_list_ptr = (sysvshm_shm *) zend_list_find(Z_LVAL_PP(arg_id), &type);
197 6 : if (!shm_list_ptr || type != php_sysvshm.le_shm) {
198 4 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "The parameter is not a valid shm_identifier");
199 4 : RETURN_FALSE;
200 : }
201 :
202 2 : zend_list_delete(Z_LVAL_PP(arg_id));
203 :
204 2 : RETURN_TRUE;
205 : }
206 : /* }}} */
207 :
208 : /* {{{ proto bool shm_remove(int shm_identifier)
209 : Removes shared memory from Unix systems */
210 : PHP_FUNCTION(shm_remove)
211 20 : {
212 : zval **arg_id;
213 : long id;
214 : int type;
215 : sysvshm_shm *shm_list_ptr;
216 :
217 20 : if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &arg_id) == FAILURE) {
218 1 : WRONG_PARAM_COUNT;
219 : }
220 :
221 19 : convert_to_long_ex(arg_id);
222 19 : id = Z_LVAL_PP(arg_id);
223 19 : shm_list_ptr = (sysvshm_shm *) zend_list_find(id, &type);
224 :
225 19 : if (!shm_list_ptr || type != php_sysvshm.le_shm) {
226 8 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "The parameter is not a valid shm_identifier");
227 8 : RETURN_FALSE;
228 : }
229 :
230 11 : if (shmctl(shm_list_ptr->id, IPC_RMID,NULL) < 0) {
231 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed for key 0x%x, id %ld: %s", shm_list_ptr->key, id, strerror(errno));
232 0 : RETURN_FALSE;
233 : }
234 :
235 11 : RETURN_TRUE;
236 : }
237 : /* }}} */
238 :
239 : /* {{{ proto bool shm_put_var(int shm_identifier, int variable_key, mixed variable)
240 : Inserts or updates a variable in shared memory */
241 : PHP_FUNCTION(shm_put_var)
242 18 : {
243 : zval **arg_id, **arg_key, **arg_var;
244 : long key, id;
245 : sysvshm_shm *shm_list_ptr;
246 : int type;
247 18 : smart_str shm_var = {0};
248 : int ret;
249 : php_serialize_data_t var_hash;
250 :
251 18 : if (ZEND_NUM_ARGS() != 3 || zend_get_parameters_ex(3, &arg_id, &arg_key, &arg_var) == FAILURE) {
252 1 : WRONG_PARAM_COUNT;
253 : }
254 :
255 17 : convert_to_long_ex(arg_id);
256 17 : id = Z_LVAL_PP(arg_id);
257 17 : convert_to_long_ex(arg_key);
258 17 : key = Z_LVAL_PP(arg_key);
259 :
260 17 : shm_list_ptr = (sysvshm_shm *) zend_list_find(id, &type);
261 17 : if (!shm_list_ptr || type != php_sysvshm.le_shm) {
262 2 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "%ld is not a SysV shared memory index", id);
263 2 : RETURN_FALSE;
264 : }
265 :
266 : /* setup string-variable and serialize */
267 :
268 15 : PHP_VAR_SERIALIZE_INIT(var_hash);
269 15 : php_var_serialize(&shm_var, arg_var, &var_hash TSRMLS_CC);
270 15 : PHP_VAR_SERIALIZE_DESTROY(var_hash);
271 : /* insert serialized variable into shared memory */
272 15 : ret = php_put_shm_data(shm_list_ptr->ptr, key, shm_var.c, shm_var.len);
273 :
274 : /* free string */
275 15 : smart_str_free(&shm_var);
276 :
277 15 : if (ret == -1) {
278 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "not enough shared memory left");
279 1 : RETURN_FALSE;
280 : }
281 14 : RETURN_TRUE;
282 : }
283 : /* }}} */
284 :
285 : /* {{{ proto mixed shm_get_var(int id, int variable_key)
286 : Returns a variable from shared memory */
287 : PHP_FUNCTION(shm_get_var)
288 16 : {
289 : zval **arg_id, **arg_key;
290 : long key, id;
291 : sysvshm_shm *shm_list_ptr;
292 : int type;
293 : char *shm_data;
294 : long shm_varpos;
295 : sysvshm_chunk *shm_var;
296 : php_unserialize_data_t var_hash;
297 :
298 16 : if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &arg_id, &arg_key) == FAILURE) {
299 1 : WRONG_PARAM_COUNT;
300 : }
301 :
302 15 : convert_to_long_ex(arg_id);
303 15 : id = Z_LVAL_PP(arg_id);
304 15 : convert_to_long_ex(arg_key);
305 15 : key = Z_LVAL_PP(arg_key);
306 :
307 15 : shm_list_ptr = (sysvshm_shm *) zend_list_find(id, &type);
308 15 : if (!shm_list_ptr || type != php_sysvshm.le_shm) {
309 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "%ld is not a SysV shared memory index", id);
310 1 : RETURN_FALSE;
311 : }
312 :
313 : /* setup string-variable and serialize */
314 : /* get serialized variable from shared memory */
315 14 : shm_varpos = php_check_shm_data((shm_list_ptr->ptr), key);
316 :
317 14 : if (shm_varpos < 0) {
318 4 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "variable key %ld doesn't exist", key);
319 4 : RETURN_FALSE;
320 : }
321 10 : shm_var = (sysvshm_chunk*) ((char *)shm_list_ptr->ptr + shm_varpos);
322 10 : shm_data = &shm_var->mem;
323 :
324 10 : PHP_VAR_UNSERIALIZE_INIT(var_hash);
325 10 : if (php_var_unserialize(&return_value, (const unsigned char **) &shm_data, shm_data + shm_var->length, &var_hash TSRMLS_CC) != 1) {
326 0 : PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
327 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "variable data in shared memory is corrupted");
328 0 : RETURN_FALSE;
329 : }
330 10 : PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
331 : }
332 : /* }}} */
333 :
334 : /* {{{ proto bool shm_remove_var(int id, int variable_key)
335 : Removes variable from shared memory */
336 : PHP_FUNCTION(shm_remove_var)
337 5 : {
338 : zval **arg_id, **arg_key;
339 : long key, id;
340 : sysvshm_shm *shm_list_ptr;
341 : int type;
342 : long shm_varpos;
343 :
344 5 : if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &arg_id, &arg_key) == FAILURE) {
345 1 : WRONG_PARAM_COUNT;
346 : }
347 :
348 4 : convert_to_long_ex(arg_id);
349 4 : id = Z_LVAL_PP(arg_id);
350 4 : convert_to_long_ex(arg_key);
351 4 : key = Z_LVAL_PP(arg_key);
352 :
353 4 : shm_list_ptr = (sysvshm_shm *) zend_list_find(id, &type);
354 4 : if (!shm_list_ptr || type != php_sysvshm.le_shm) {
355 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "%ld is not a SysV shared memory index", id);
356 1 : RETURN_FALSE;
357 : }
358 :
359 3 : shm_varpos = php_check_shm_data((shm_list_ptr->ptr), key);
360 :
361 3 : if (shm_varpos < 0) {
362 2 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "variable key %ld doesn't exist", key);
363 2 : RETURN_FALSE;
364 : }
365 1 : php_remove_shm_data((shm_list_ptr->ptr), shm_varpos);
366 1 : RETURN_TRUE;
367 : }
368 : /* }}} */
369 :
370 : /* {{{ php_put_shm_data
371 : * inserts an ascii-string into shared memory */
372 : static int php_put_shm_data(sysvshm_chunk_head *ptr, long key, char *data, long len)
373 15 : {
374 : sysvshm_chunk *shm_var;
375 : long total_size;
376 : long shm_varpos;
377 :
378 15 : total_size = ((long) (len + sizeof(sysvshm_chunk) - 1) / sizeof(long)) * sizeof(long) + sizeof(long); /* long alligment */
379 :
380 15 : if ((shm_varpos = php_check_shm_data(ptr, key)) > 0) {
381 4 : php_remove_shm_data(ptr, shm_varpos);
382 : }
383 :
384 15 : if (ptr->free < total_size) {
385 1 : return -1; /* not enough memeory */
386 : }
387 :
388 14 : shm_var = (sysvshm_chunk *) ((char *) ptr + ptr->end);
389 14 : shm_var->key = key;
390 14 : shm_var->length = len;
391 14 : shm_var->next = total_size;
392 14 : memcpy(&(shm_var->mem), data, len);
393 14 : ptr->end += total_size;
394 14 : ptr->free -= total_size;
395 14 : return 0;
396 : }
397 : /* }}} */
398 :
399 : /* {{{ php_check_shm_data
400 : */
401 : static long php_check_shm_data(sysvshm_chunk_head *ptr, long key)
402 32 : {
403 : long pos;
404 : sysvshm_chunk *shm_var;
405 :
406 32 : pos = ptr->start;
407 :
408 : for (;;) {
409 86 : if (pos >= ptr->end) {
410 17 : return -1;
411 : }
412 69 : shm_var = (sysvshm_chunk*) ((char *) ptr + pos);
413 69 : if (shm_var->key == key) {
414 15 : return pos;
415 : }
416 54 : pos += shm_var->next;
417 :
418 54 : if (shm_var->next <= 0 || pos < ptr->start) {
419 0 : return -1;
420 : }
421 54 : }
422 : return -1;
423 : }
424 : /* }}} */
425 :
426 : /* {{{ php_remove_shm_data
427 : */
428 : static int php_remove_shm_data(sysvshm_chunk_head *ptr, long shm_varpos)
429 5 : {
430 : sysvshm_chunk *chunk_ptr, *next_chunk_ptr;
431 : long memcpy_len;
432 :
433 5 : chunk_ptr = (sysvshm_chunk *) ((char *) ptr + shm_varpos);
434 5 : next_chunk_ptr = (sysvshm_chunk *) ((char *) ptr + shm_varpos + chunk_ptr->next);
435 :
436 5 : memcpy_len = ptr->end-shm_varpos - chunk_ptr->next;
437 5 : ptr->free += chunk_ptr->next;
438 5 : ptr->end -= chunk_ptr->next;
439 5 : if (memcpy_len > 0) {
440 0 : memcpy(chunk_ptr, next_chunk_ptr, memcpy_len);
441 : }
442 5 : return 0;
443 : }
444 : /* }}} */
445 :
446 : #endif /* HAVE_SYSVSHM */
447 :
448 : /*
449 : * Local variables:
450 : * tab-width: 4
451 : * c-basic-offset: 4
452 : * End:
453 : * vim600: sw=4 ts=4 fdm=marker
454 : * vim<600: sw=4 ts=4
455 : */
|