1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP version 4 |
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 : | Authors: Slava Poliakov <hackie@prohost.org> |
16 : | Ilia Alshanetsky <ilia@prohost.org> |
17 : +----------------------------------------------------------------------+
18 : */
19 : /* $Id: shmop.c 281741 2009-06-06 02:40:14Z mattwil $ */
20 :
21 : #ifdef HAVE_CONFIG_H
22 : #include "config.h"
23 : #endif
24 :
25 : #include "php.h"
26 : #include "php_ini.h"
27 : #include "php_shmop.h"
28 : # ifndef PHP_WIN32
29 : # include <sys/ipc.h>
30 : # include <sys/shm.h>
31 : #else
32 : #include "tsrm_win32.h"
33 : #endif
34 :
35 :
36 : #if HAVE_SHMOP
37 :
38 : #include "ext/standard/info.h"
39 :
40 : #ifdef ZTS
41 : int shmop_globals_id;
42 : #else
43 : php_shmop_globals shmop_globals;
44 : #endif
45 :
46 : int shm_type;
47 :
48 : /* {{{ arginfo */
49 : ZEND_BEGIN_ARG_INFO_EX(arginfo_shmop_open, 0, 0, 4)
50 : ZEND_ARG_INFO(0, key)
51 : ZEND_ARG_INFO(0, flags)
52 : ZEND_ARG_INFO(0, mode)
53 : ZEND_ARG_INFO(0, size)
54 : ZEND_END_ARG_INFO()
55 :
56 : ZEND_BEGIN_ARG_INFO_EX(arginfo_shmop_read, 0, 0, 3)
57 : ZEND_ARG_INFO(0, shmid)
58 : ZEND_ARG_INFO(0, start)
59 : ZEND_ARG_INFO(0, count)
60 : ZEND_END_ARG_INFO()
61 :
62 : ZEND_BEGIN_ARG_INFO_EX(arginfo_shmop_close, 0, 0, 1)
63 : ZEND_ARG_INFO(0, shmid)
64 : ZEND_END_ARG_INFO()
65 :
66 : ZEND_BEGIN_ARG_INFO_EX(arginfo_shmop_size, 0, 0, 1)
67 : ZEND_ARG_INFO(0, shmid)
68 : ZEND_END_ARG_INFO()
69 :
70 : ZEND_BEGIN_ARG_INFO_EX(arginfo_shmop_write, 0, 0, 3)
71 : ZEND_ARG_INFO(0, shmid)
72 : ZEND_ARG_INFO(0, data)
73 : ZEND_ARG_INFO(0, offset)
74 : ZEND_END_ARG_INFO()
75 :
76 : ZEND_BEGIN_ARG_INFO_EX(arginfo_shmop_delete, 0, 0, 1)
77 : ZEND_ARG_INFO(0, shmid)
78 : ZEND_END_ARG_INFO()
79 : /* }}} */
80 :
81 : /* {{{ shmop_functions[]
82 : */
83 : const zend_function_entry shmop_functions[] = {
84 : PHP_FE(shmop_open, arginfo_shmop_open)
85 : PHP_FE(shmop_read, arginfo_shmop_read)
86 : PHP_FE(shmop_close, arginfo_shmop_close)
87 : PHP_FE(shmop_size, arginfo_shmop_size)
88 : PHP_FE(shmop_write, arginfo_shmop_write)
89 : PHP_FE(shmop_delete, arginfo_shmop_delete)
90 : {NULL, NULL, NULL} /* Must be the last line in shmop_functions[] */
91 : };
92 : /* }}} */
93 :
94 : /* {{{ shmop_module_entry
95 : */
96 : zend_module_entry shmop_module_entry = {
97 : STANDARD_MODULE_HEADER,
98 : "shmop",
99 : shmop_functions,
100 : PHP_MINIT(shmop),
101 : NULL,
102 : NULL,
103 : NULL,
104 : PHP_MINFO(shmop),
105 : NO_VERSION_YET,
106 : STANDARD_MODULE_PROPERTIES
107 : };
108 : /* }}} */
109 :
110 : #ifdef COMPILE_DL_SHMOP
111 : ZEND_GET_MODULE(shmop)
112 : #endif
113 :
114 : #define PHP_SHMOP_GET_RES \
115 : shmop = zend_list_find(shmid, &type); \
116 : if (!shmop) { \
117 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "no shared memory segment with an id of [%lu]", shmid); \
118 : RETURN_FALSE; \
119 : } else if (type != shm_type) { \
120 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "not a shmop resource"); \
121 : RETURN_FALSE; \
122 : } \
123 :
124 : /* {{{ rsclean
125 : */
126 : static void rsclean(zend_rsrc_list_entry *rsrc TSRMLS_DC)
127 3 : {
128 3 : struct php_shmop *shmop = (struct php_shmop *)rsrc->ptr;
129 :
130 3 : shmdt(shmop->addr);
131 3 : efree(shmop);
132 3 : }
133 : /* }}} */
134 :
135 : /* {{{ PHP_MINIT_FUNCTION
136 : */
137 : PHP_MINIT_FUNCTION(shmop)
138 17007 : {
139 17007 : shm_type = zend_register_list_destructors_ex(rsclean, NULL, "shmop", module_number);
140 :
141 17007 : return SUCCESS;
142 : }
143 : /* }}} */
144 :
145 : /* {{{ PHP_MINFO_FUNCTION
146 : */
147 : PHP_MINFO_FUNCTION(shmop)
148 43 : {
149 43 : php_info_print_table_start();
150 43 : php_info_print_table_row(2, "shmop support", "enabled");
151 43 : php_info_print_table_end();
152 43 : }
153 : /* }}} */
154 :
155 : /* {{{ proto int shmop_open (int key, string flags, int mode, int size) U
156 : gets and attaches a shared memory segment */
157 : PHP_FUNCTION(shmop_open)
158 3 : {
159 : long key, mode, size;
160 : struct php_shmop *shmop;
161 : struct shmid_ds shm;
162 : int rsid;
163 : char *flags;
164 : int flags_len;
165 : zend_uchar flag_type;
166 :
167 3 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ltll", &key, &flags, &flags_len, &flag_type, &mode, &size) == FAILURE) {
168 0 : return;
169 : }
170 :
171 3 : if (flag_type == IS_UNICODE) {
172 3 : flags = zend_unicode_to_ascii((UChar*)flags, flags_len TSRMLS_CC);
173 3 : if (!flags) {
174 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Binary or ASCII-Unicode string expected, non-ASCII-Unicode string received");
175 0 : RETURN_FALSE;
176 : }
177 : }
178 :
179 3 : if (flags_len != 1) {
180 0 : if (flag_type == IS_UNICODE) {
181 0 : efree(flags);
182 : }
183 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s is not a valid flag", flags);
184 0 : RETURN_FALSE;
185 : }
186 :
187 3 : shmop = emalloc(sizeof(struct php_shmop));
188 3 : memset(shmop, 0, sizeof(struct php_shmop));
189 :
190 3 : shmop->key = key;
191 3 : shmop->shmflg |= mode;
192 :
193 3 : switch (flags[0])
194 : {
195 : case 'a':
196 1 : shmop->shmatflg |= SHM_RDONLY;
197 1 : break;
198 : case 'c':
199 0 : shmop->shmflg |= IPC_CREAT;
200 0 : shmop->size = size;
201 0 : break;
202 : case 'n':
203 1 : shmop->shmflg |= (IPC_CREAT | IPC_EXCL);
204 1 : shmop->size = size;
205 1 : break;
206 : case 'w':
207 : /* noop
208 : shm segment is being opened for read & write
209 : will fail if segment does not exist
210 : */
211 1 : break;
212 : default:
213 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid access mode");
214 0 : goto err;
215 : }
216 :
217 3 : if (shmop->shmflg & IPC_CREAT && shmop->size < 1) {
218 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Shared memory segment size must be greater than zero");
219 0 : goto err;
220 : }
221 :
222 3 : shmop->shmid = shmget(shmop->key, shmop->size, shmop->shmflg);
223 3 : if (shmop->shmid == -1) {
224 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to attach or create shared memory segment");
225 0 : goto err;
226 : }
227 :
228 3 : if (shmctl(shmop->shmid, IPC_STAT, &shm)) {
229 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to get shared memory segment information");
230 0 : goto err;
231 : }
232 :
233 3 : shmop->addr = shmat(shmop->shmid, 0, shmop->shmatflg);
234 3 : if (shmop->addr == (char*) -1) {
235 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to attach to shared memory segment");
236 0 : goto err;
237 : }
238 :
239 3 : shmop->size = shm.shm_segsz;
240 :
241 3 : rsid = zend_list_insert(shmop, shm_type);
242 3 : if (flag_type == IS_UNICODE) {
243 3 : efree(flags);
244 : }
245 3 : RETURN_LONG(rsid);
246 0 : err:
247 0 : if (flag_type == IS_UNICODE) {
248 0 : efree(flags);
249 : }
250 0 : efree(shmop);
251 0 : RETURN_FALSE;
252 : }
253 : /* }}} */
254 :
255 : /* {{{ proto string shmop_read (int shmid, int start, int count) U
256 : reads from a shm segment */
257 : PHP_FUNCTION(shmop_read)
258 3 : {
259 : long shmid, start, count;
260 : struct php_shmop *shmop;
261 : int type;
262 : char *startaddr;
263 : int bytes;
264 :
265 3 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lll", &shmid, &start, &count) == FAILURE) {
266 0 : return;
267 : }
268 :
269 3 : PHP_SHMOP_GET_RES
270 :
271 3 : if (start < 0 || start > shmop->size) {
272 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "start is out of range");
273 0 : RETURN_FALSE;
274 : }
275 :
276 3 : if (start + count > shmop->size || count < 0) {
277 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "count is out of range");
278 0 : RETURN_FALSE;
279 : }
280 :
281 3 : startaddr = shmop->addr + start;
282 3 : bytes = count ? count : shmop->size - start;
283 :
284 3 : RETURN_STRINGL(startaddr, bytes, 1);
285 : }
286 : /* }}} */
287 :
288 : /* {{{ proto void shmop_close (int shmid) U
289 : closes a shared memory segment */
290 : PHP_FUNCTION(shmop_close)
291 3 : {
292 : long shmid;
293 : struct php_shmop *shmop;
294 : int type;
295 :
296 3 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &shmid) == FAILURE) {
297 0 : return;
298 : }
299 :
300 3 : PHP_SHMOP_GET_RES
301 :
302 3 : zend_list_delete(shmid);
303 : }
304 : /* }}} */
305 :
306 : /* {{{ proto int shmop_size (int shmid) U
307 : returns the shm size */
308 : PHP_FUNCTION(shmop_size)
309 1 : {
310 : long shmid;
311 : struct php_shmop *shmop;
312 : int type;
313 :
314 1 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &shmid) == FAILURE) {
315 0 : return;
316 : }
317 :
318 1 : PHP_SHMOP_GET_RES
319 :
320 1 : RETURN_LONG(shmop->size);
321 : }
322 : /* }}} */
323 :
324 : /* {{{ proto int shmop_write (int shmid, string data, int offset) U
325 : writes to a shared memory segment */
326 : PHP_FUNCTION(shmop_write)
327 3 : {
328 : struct php_shmop *shmop;
329 : int type;
330 : int writesize;
331 3 : long shmid, offset=0;
332 : char *data;
333 : int data_len;
334 :
335 3 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lS|l", &shmid, &data, &data_len, &offset) == FAILURE) {
336 0 : return;
337 : }
338 :
339 3 : PHP_SHMOP_GET_RES
340 :
341 3 : if ((shmop->shmatflg & SHM_RDONLY) == SHM_RDONLY) {
342 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "trying to write to a read only segment");
343 1 : RETURN_FALSE;
344 : }
345 :
346 2 : if (offset < 0 || offset > shmop->size) {
347 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "offset out of range");
348 0 : RETURN_FALSE;
349 : }
350 :
351 2 : writesize = (data_len < shmop->size - offset) ? data_len : shmop->size - offset;
352 2 : memcpy(shmop->addr + offset, data, writesize);
353 :
354 2 : RETURN_LONG(writesize);
355 : }
356 : /* }}} */
357 :
358 : /* {{{ proto bool shmop_delete (int shmid) U
359 : mark segment for deletion */
360 : PHP_FUNCTION(shmop_delete)
361 1 : {
362 : long shmid;
363 : struct php_shmop *shmop;
364 : int type;
365 :
366 1 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &shmid) == FAILURE) {
367 0 : return;
368 : }
369 :
370 1 : PHP_SHMOP_GET_RES
371 :
372 1 : if (shmctl(shmop->shmid, IPC_RMID, NULL)) {
373 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "can't mark segment for deletion (are you the owner?)");
374 0 : RETURN_FALSE;
375 : }
376 :
377 1 : RETURN_TRUE;
378 : }
379 : /* }}} */
380 :
381 : #endif /* HAVE_SHMOP */
382 :
383 : /*
384 : * Local variables:
385 : * tab-width: 4
386 : * c-basic-offset: 4
387 : * End:
388 : * vim600: sw=4 ts=4 fdm=marker
389 : * vim<600: sw=4 ts=4
390 : */
|