1 /*
2 +----------------------------------------------------------------------+
3 | PHP version 5 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2014 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$ */
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 PHP_FE_END
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
ZEND_GET_MODULE(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 {
128 struct php_shmop *shmop = (struct php_shmop *)rsrc->ptr;
129
130 shmdt(shmop->addr);
131 efree(shmop);
132 }
133 /* }}} */
134
135 /* {{{ PHP_MINIT_FUNCTION
136 */
PHP_MINIT_FUNCTION(shmop)137 PHP_MINIT_FUNCTION(shmop)
138 {
139 shm_type = zend_register_list_destructors_ex(rsclean, NULL, "shmop", module_number);
140
141 return SUCCESS;
142 }
143 /* }}} */
144
145 /* {{{ PHP_MINFO_FUNCTION
146 */
PHP_MINFO_FUNCTION(shmop)147 PHP_MINFO_FUNCTION(shmop)
148 {
149 php_info_print_table_start();
150 php_info_print_table_row(2, "shmop support", "enabled");
151 php_info_print_table_end();
152 }
153 /* }}} */
154
155 /* {{{ proto int shmop_open (int key, string flags, int mode, int size)
156 gets and attaches a shared memory segment */
PHP_FUNCTION(shmop_open)157 PHP_FUNCTION(shmop_open)
158 {
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
166 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lsll", &key, &flags, &flags_len, &mode, &size) == FAILURE) {
167 return;
168 }
169
170 if (flags_len != 1) {
171 php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s is not a valid flag", flags);
172 RETURN_FALSE;
173 }
174
175 shmop = emalloc(sizeof(struct php_shmop));
176 memset(shmop, 0, sizeof(struct php_shmop));
177
178 shmop->key = key;
179 shmop->shmflg |= mode;
180
181 switch (flags[0])
182 {
183 case 'a':
184 shmop->shmatflg |= SHM_RDONLY;
185 break;
186 case 'c':
187 shmop->shmflg |= IPC_CREAT;
188 shmop->size = size;
189 break;
190 case 'n':
191 shmop->shmflg |= (IPC_CREAT | IPC_EXCL);
192 shmop->size = size;
193 break;
194 case 'w':
195 /* noop
196 shm segment is being opened for read & write
197 will fail if segment does not exist
198 */
199 break;
200 default:
201 php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid access mode");
202 goto err;
203 }
204
205 if (shmop->shmflg & IPC_CREAT && shmop->size < 1) {
206 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Shared memory segment size must be greater than zero");
207 goto err;
208 }
209
210 shmop->shmid = shmget(shmop->key, shmop->size, shmop->shmflg);
211 if (shmop->shmid == -1) {
212 php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to attach or create shared memory segment");
213 goto err;
214 }
215
216 if (shmctl(shmop->shmid, IPC_STAT, &shm)) {
217 php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to get shared memory segment information");
218 goto err;
219 }
220
221 shmop->addr = shmat(shmop->shmid, 0, shmop->shmatflg);
222 if (shmop->addr == (char*) -1) {
223 php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to attach to shared memory segment");
224 goto err;
225 }
226
227 shmop->size = shm.shm_segsz;
228
229 rsid = zend_list_insert(shmop, shm_type TSRMLS_CC);
230 RETURN_LONG(rsid);
231 err:
232 efree(shmop);
233 RETURN_FALSE;
234 }
235 /* }}} */
236
237 /* {{{ proto string shmop_read (int shmid, int start, int count)
238 reads from a shm segment */
PHP_FUNCTION(shmop_read)239 PHP_FUNCTION(shmop_read)
240 {
241 long shmid, start, count;
242 struct php_shmop *shmop;
243 int type;
244 char *startaddr;
245 int bytes;
246 char *return_string;
247
248 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lll", &shmid, &start, &count) == FAILURE) {
249 return;
250 }
251
252 PHP_SHMOP_GET_RES
253
254 if (start < 0 || start > shmop->size) {
255 php_error_docref(NULL TSRMLS_CC, E_WARNING, "start is out of range");
256 RETURN_FALSE;
257 }
258
259 if (count < 0 || start > (INT_MAX - count) || start + count > shmop->size) {
260 php_error_docref(NULL TSRMLS_CC, E_WARNING, "count is out of range");
261 RETURN_FALSE;
262 }
263
264 startaddr = shmop->addr + start;
265 bytes = count ? count : shmop->size - start;
266
267 return_string = emalloc(bytes+1);
268 memcpy(return_string, startaddr, bytes);
269 return_string[bytes] = 0;
270
271 RETURN_STRINGL(return_string, bytes, 0);
272 }
273 /* }}} */
274
275 /* {{{ proto void shmop_close (int shmid)
276 closes a shared memory segment */
PHP_FUNCTION(shmop_close)277 PHP_FUNCTION(shmop_close)
278 {
279 long shmid;
280 struct php_shmop *shmop;
281 int type;
282
283 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &shmid) == FAILURE) {
284 return;
285 }
286
287 PHP_SHMOP_GET_RES
288
289 zend_list_delete(shmid);
290 }
291 /* }}} */
292
293 /* {{{ proto int shmop_size (int shmid)
294 returns the shm size */
PHP_FUNCTION(shmop_size)295 PHP_FUNCTION(shmop_size)
296 {
297 long shmid;
298 struct php_shmop *shmop;
299 int type;
300
301 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &shmid) == FAILURE) {
302 return;
303 }
304
305 PHP_SHMOP_GET_RES
306
307 RETURN_LONG(shmop->size);
308 }
309 /* }}} */
310
311 /* {{{ proto int shmop_write (int shmid, string data, int offset)
312 writes to a shared memory segment */
PHP_FUNCTION(shmop_write)313 PHP_FUNCTION(shmop_write)
314 {
315 struct php_shmop *shmop;
316 int type;
317 int writesize;
318 long shmid, offset;
319 char *data;
320 int data_len;
321
322 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lsl", &shmid, &data, &data_len, &offset) == FAILURE) {
323 return;
324 }
325
326 PHP_SHMOP_GET_RES
327
328 if ((shmop->shmatflg & SHM_RDONLY) == SHM_RDONLY) {
329 php_error_docref(NULL TSRMLS_CC, E_WARNING, "trying to write to a read only segment");
330 RETURN_FALSE;
331 }
332
333 if (offset < 0 || offset > shmop->size) {
334 php_error_docref(NULL TSRMLS_CC, E_WARNING, "offset out of range");
335 RETURN_FALSE;
336 }
337
338 writesize = (data_len < shmop->size - offset) ? data_len : shmop->size - offset;
339 memcpy(shmop->addr + offset, data, writesize);
340
341 RETURN_LONG(writesize);
342 }
343 /* }}} */
344
345 /* {{{ proto bool shmop_delete (int shmid)
346 mark segment for deletion */
PHP_FUNCTION(shmop_delete)347 PHP_FUNCTION(shmop_delete)
348 {
349 long shmid;
350 struct php_shmop *shmop;
351 int type;
352
353 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &shmid) == FAILURE) {
354 return;
355 }
356
357 PHP_SHMOP_GET_RES
358
359 if (shmctl(shmop->shmid, IPC_RMID, NULL)) {
360 php_error_docref(NULL TSRMLS_CC, E_WARNING, "can't mark segment for deletion (are you the owner?)");
361 RETURN_FALSE;
362 }
363
364 RETURN_TRUE;
365 }
366 /* }}} */
367
368 #endif /* HAVE_SHMOP */
369
370 /*
371 * Local variables:
372 * tab-width: 4
373 * c-basic-offset: 4
374 * End:
375 * vim600: sw=4 ts=4 fdm=marker
376 * vim<600: sw=4 ts=4
377 */
378