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: Wez Furlong <wez@thebrainroom.com> |
16 : +----------------------------------------------------------------------+
17 : */
18 :
19 : /* $Id: sysvmsg.c 272374 2008-12-31 11:17:49Z sebastian $ */
20 :
21 : #ifdef HAVE_CONFIG_H
22 : #include "config.h"
23 : #endif
24 :
25 : #include "php.h"
26 : #include "php_globals.h"
27 : #include "ext/standard/info.h"
28 : #include "php_sysvmsg.h"
29 : #include "ext/standard/php_var.h"
30 : #include "ext/standard/php_smart_str.h"
31 :
32 : /* In order to detect MSG_EXCEPT use at run time; we have no way
33 : * of knowing what the bit definitions are, so we can't just define
34 : * out own MSG_EXCEPT value. */
35 : #define PHP_MSG_IPC_NOWAIT 1
36 : #define PHP_MSG_NOERROR 2
37 : #define PHP_MSG_EXCEPT 4
38 :
39 : /* True global resources - no need for thread safety here */
40 : static int le_sysvmsg;
41 :
42 : static
43 : ZEND_BEGIN_ARG_INFO(sixth_arg_force_ref, 0)
44 : ZEND_ARG_PASS_INFO(0)
45 : ZEND_ARG_PASS_INFO(0)
46 : ZEND_ARG_PASS_INFO(0)
47 : ZEND_ARG_PASS_INFO(0)
48 : ZEND_ARG_PASS_INFO(0)
49 : ZEND_ARG_PASS_INFO(1)
50 : ZEND_END_ARG_INFO();
51 :
52 : static
53 : ZEND_BEGIN_ARG_INFO(msg_receive_args_force_ref, 0)
54 : ZEND_ARG_PASS_INFO(0)
55 : ZEND_ARG_PASS_INFO(0)
56 : ZEND_ARG_PASS_INFO(1)
57 : ZEND_ARG_PASS_INFO(0)
58 : ZEND_ARG_PASS_INFO(1)
59 : ZEND_ARG_PASS_INFO(0)
60 : ZEND_ARG_PASS_INFO(0)
61 : ZEND_ARG_PASS_INFO(1)
62 : ZEND_END_ARG_INFO();
63 :
64 : /* {{{ sysvmsg_functions[]
65 : *
66 : * Every user visible function must have an entry in sysvmsg_functions[].
67 : */
68 : zend_function_entry sysvmsg_functions[] = {
69 : PHP_FE(msg_get_queue, NULL)
70 : PHP_FE(msg_send, sixth_arg_force_ref)
71 : PHP_FE(msg_receive, msg_receive_args_force_ref)
72 : PHP_FE(msg_remove_queue, NULL)
73 : PHP_FE(msg_stat_queue, NULL)
74 : PHP_FE(msg_set_queue, NULL)
75 : {NULL, NULL, NULL} /* Must be the last line in sysvmsg_functions[] */
76 : };
77 : /* }}} */
78 :
79 : /* {{{ sysvmsg_module_entry
80 : */
81 : zend_module_entry sysvmsg_module_entry = {
82 : STANDARD_MODULE_HEADER,
83 : "sysvmsg",
84 : sysvmsg_functions,
85 : PHP_MINIT(sysvmsg),
86 : NULL,
87 : NULL,
88 : NULL,
89 : PHP_MINFO(sysvmsg),
90 : NO_VERSION_YET,
91 : STANDARD_MODULE_PROPERTIES
92 : };
93 : /* }}} */
94 :
95 : #ifdef COMPILE_DL_SYSVMSG
96 : ZEND_GET_MODULE(sysvmsg)
97 : # ifdef PHP_WIN32
98 : # include "zend_arg_defs.c"
99 : # endif
100 : #endif
101 :
102 : static void sysvmsg_release(zend_rsrc_list_entry *rsrc TSRMLS_DC)
103 2 : {
104 2 : sysvmsg_queue_t * mq = (sysvmsg_queue_t *) rsrc->ptr;
105 2 : efree(mq);
106 2 : }
107 :
108 : /* {{{ PHP_MINIT_FUNCTION
109 : */
110 : PHP_MINIT_FUNCTION(sysvmsg)
111 13565 : {
112 13565 : le_sysvmsg = zend_register_list_destructors_ex(sysvmsg_release, NULL, "sysvmsg queue", module_number);
113 13565 : REGISTER_LONG_CONSTANT("MSG_IPC_NOWAIT", PHP_MSG_IPC_NOWAIT, CONST_PERSISTENT|CONST_CS);
114 13565 : REGISTER_LONG_CONSTANT("MSG_EAGAIN", EAGAIN, CONST_PERSISTENT|CONST_CS);
115 13565 : REGISTER_LONG_CONSTANT("MSG_ENOMSG", ENOMSG, CONST_PERSISTENT|CONST_CS);
116 13565 : REGISTER_LONG_CONSTANT("MSG_NOERROR", PHP_MSG_NOERROR, CONST_PERSISTENT|CONST_CS);
117 13565 : REGISTER_LONG_CONSTANT("MSG_EXCEPT", PHP_MSG_EXCEPT, CONST_PERSISTENT|CONST_CS);
118 13565 : return SUCCESS;
119 : }
120 : /* }}} */
121 :
122 : /* {{{ PHP_MINFO_FUNCTION
123 : */
124 : PHP_MINFO_FUNCTION(sysvmsg)
125 6 : {
126 6 : php_info_print_table_start();
127 6 : php_info_print_table_row(2, "sysvmsg support", "enabled");
128 6 : php_info_print_table_row(2, "Revision", "$Revision: 272374 $");
129 6 : php_info_print_table_end();
130 6 : }
131 : /* }}} */
132 :
133 : /* {{{ proto bool msg_set_queue(resource queue, array data)
134 : Set information for a message queue */
135 : PHP_FUNCTION(msg_set_queue)
136 0 : {
137 : zval *queue, *data;
138 0 : sysvmsg_queue_t *mq = NULL;
139 : struct msqid_ds stat;
140 :
141 0 : RETVAL_FALSE;
142 :
143 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ra", &queue, &data) == FAILURE) {
144 0 : return;
145 : }
146 :
147 0 : ZEND_FETCH_RESOURCE(mq, sysvmsg_queue_t *, &queue, -1, "sysvmsg queue", le_sysvmsg);
148 :
149 0 : if (msgctl(mq->id, IPC_STAT, &stat) == 0) {
150 : zval **item;
151 :
152 : /* now pull out members of data and set them in the stat buffer */
153 0 : if (zend_hash_find(Z_ARRVAL_P(data), "msg_perm.uid", sizeof("msg_perm.uid"), (void **) &item) == SUCCESS) {
154 0 : convert_to_long_ex(item);
155 0 : stat.msg_perm.uid = Z_LVAL_PP(item);
156 : }
157 0 : if (zend_hash_find(Z_ARRVAL_P(data), "msg_perm.gid", sizeof("msg_perm.gid"), (void **) &item) == SUCCESS) {
158 0 : convert_to_long_ex(item);
159 0 : stat.msg_perm.gid = Z_LVAL_PP(item);
160 : }
161 0 : if (zend_hash_find(Z_ARRVAL_P(data), "msg_perm.mode", sizeof("msg_perm.mode"), (void **) &item) == SUCCESS) {
162 0 : convert_to_long_ex(item);
163 0 : stat.msg_perm.mode = Z_LVAL_PP(item);
164 : }
165 0 : if (zend_hash_find(Z_ARRVAL_P(data), "msg_qbytes", sizeof("msg_qbytes"), (void **) &item) == SUCCESS) {
166 0 : convert_to_long_ex(item);
167 0 : stat.msg_qbytes = Z_LVAL_PP(item);
168 : }
169 0 : if (msgctl(mq->id, IPC_SET, &stat) == 0) {
170 0 : RETVAL_TRUE;
171 : }
172 : }
173 : }
174 : /* }}} */
175 :
176 : /* {{{ proto array msg_stat_queue(resource queue)
177 : Returns information about a message queue */
178 : PHP_FUNCTION(msg_stat_queue)
179 0 : {
180 : zval *queue;
181 0 : sysvmsg_queue_t *mq = NULL;
182 : struct msqid_ds stat;
183 :
184 0 : RETVAL_FALSE;
185 :
186 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &queue) == FAILURE) {
187 0 : return;
188 : }
189 :
190 0 : ZEND_FETCH_RESOURCE(mq, sysvmsg_queue_t *, &queue, -1, "sysvmsg queue", le_sysvmsg);
191 :
192 0 : if (msgctl(mq->id, IPC_STAT, &stat) == 0) {
193 0 : array_init(return_value);
194 :
195 0 : add_assoc_long(return_value, "msg_perm.uid", stat.msg_perm.uid);
196 0 : add_assoc_long(return_value, "msg_perm.gid", stat.msg_perm.gid);
197 0 : add_assoc_long(return_value, "msg_perm.mode", stat.msg_perm.mode);
198 0 : add_assoc_long(return_value, "msg_stime", stat.msg_stime);
199 0 : add_assoc_long(return_value, "msg_rtime", stat.msg_rtime);
200 0 : add_assoc_long(return_value, "msg_ctime", stat.msg_ctime);
201 0 : add_assoc_long(return_value, "msg_qnum", stat.msg_qnum);
202 0 : add_assoc_long(return_value, "msg_qbytes", stat.msg_qbytes);
203 0 : add_assoc_long(return_value, "msg_lspid", stat.msg_lspid);
204 0 : add_assoc_long(return_value, "msg_lrpid", stat.msg_lrpid);
205 : }
206 : }
207 : /* }}} */
208 :
209 : /* {{{ proto resource msg_get_queue(int key [, int perms])
210 : Attach to a message queue */
211 : PHP_FUNCTION(msg_get_queue)
212 2 : {
213 : long key;
214 2 : long perms = 0666;
215 : sysvmsg_queue_t *mq;
216 :
217 2 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|l", &key, &perms) == FAILURE) {
218 0 : return;
219 : }
220 :
221 2 : mq = (sysvmsg_queue_t *) emalloc(sizeof(sysvmsg_queue_t));
222 :
223 2 : mq->key = key;
224 2 : mq->id = msgget(key, 0);
225 2 : if (mq->id < 0) {
226 : /* doesn't already exist; create it */
227 2 : mq->id = msgget(key, IPC_CREAT | IPC_EXCL | perms);
228 2 : if (mq->id < 0) {
229 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed for key 0x%lx: %s", key, strerror(errno));
230 0 : efree(mq);
231 0 : RETURN_FALSE;
232 : }
233 : }
234 2 : RETVAL_RESOURCE(zend_list_insert(mq, le_sysvmsg));
235 : }
236 : /* }}} */
237 :
238 : /* {{{ proto bool msg_remove_queue(resource queue)
239 : Destroy the queue */
240 : PHP_FUNCTION(msg_remove_queue)
241 2 : {
242 : zval *queue;
243 2 : sysvmsg_queue_t *mq = NULL;
244 :
245 2 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &queue) == FAILURE) {
246 0 : return;
247 : }
248 :
249 2 : ZEND_FETCH_RESOURCE(mq, sysvmsg_queue_t *, &queue, -1, "sysvmsg queue", le_sysvmsg);
250 :
251 2 : if (msgctl(mq->id, IPC_RMID, NULL) == 0) {
252 2 : RETVAL_TRUE;
253 : } else {
254 0 : RETVAL_FALSE;
255 : }
256 : }
257 : /* }}} */
258 :
259 : /* {{{ proto mixed msg_receive(resource queue, int desiredmsgtype, int &msgtype, int maxsize, mixed message [, bool unserialize=true [, int flags=0 [, int errorcode]]])
260 : Send a message of type msgtype (must be > 0) to a message queue */
261 : PHP_FUNCTION(msg_receive)
262 2 : {
263 2 : zval *out_message, *queue, *out_msgtype, *zerrcode = NULL;
264 2 : long desiredmsgtype, maxsize, flags = 0;
265 2 : long realflags = 0;
266 2 : zend_bool do_unserialize = 1;
267 2 : sysvmsg_queue_t *mq = NULL;
268 2 : struct php_msgbuf *messagebuffer = NULL; /* buffer to transmit */
269 : int result;
270 :
271 2 : RETVAL_FALSE;
272 :
273 2 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rlzlz|blz",
274 : &queue, &desiredmsgtype, &out_msgtype, &maxsize,
275 : &out_message, &do_unserialize, &flags, &zerrcode) == FAILURE) {
276 0 : return;
277 : }
278 :
279 2 : if (maxsize <= 0) {
280 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "maximum size of the message has to be greater than zero");
281 0 : return;
282 : }
283 :
284 2 : if (flags != 0) {
285 0 : if (flags & PHP_MSG_EXCEPT) {
286 : #ifndef MSG_EXCEPT
287 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "MSG_EXCEPT is not supported on your system");
288 : RETURN_FALSE;
289 : #else
290 0 : realflags |= MSG_EXCEPT;
291 : #endif
292 : }
293 0 : if (flags & PHP_MSG_NOERROR) {
294 0 : realflags |= MSG_NOERROR;
295 : }
296 0 : if (flags & PHP_MSG_IPC_NOWAIT) {
297 0 : realflags |= IPC_NOWAIT;
298 : }
299 : }
300 :
301 2 : ZEND_FETCH_RESOURCE(mq, sysvmsg_queue_t *, &queue, -1, "sysvmsg queue", le_sysvmsg);
302 :
303 2 : messagebuffer = (struct php_msgbuf *) safe_emalloc(maxsize, 1, sizeof(struct php_msgbuf));
304 :
305 2 : result = msgrcv(mq->id, messagebuffer, maxsize, desiredmsgtype, realflags);
306 :
307 2 : zval_dtor(out_msgtype);
308 2 : zval_dtor(out_message);
309 2 : ZVAL_LONG(out_msgtype, 0);
310 2 : ZVAL_FALSE(out_message);
311 :
312 2 : if (zerrcode) {
313 1 : zval_dtor(zerrcode);
314 1 : ZVAL_LONG(zerrcode, 0);
315 : }
316 :
317 2 : if (result >= 0) {
318 : /* got it! */
319 2 : ZVAL_LONG(out_msgtype, messagebuffer->mtype);
320 :
321 2 : RETVAL_TRUE;
322 2 : if (do_unserialize) {
323 : php_unserialize_data_t var_hash;
324 2 : zval *tmp = NULL;
325 2 : const unsigned char *p = (const unsigned char *) messagebuffer->mtext;
326 :
327 2 : MAKE_STD_ZVAL(tmp);
328 2 : PHP_VAR_UNSERIALIZE_INIT(var_hash);
329 2 : if (!php_var_unserialize(&tmp, &p, p + result, &var_hash TSRMLS_CC)) {
330 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "message corrupted");
331 1 : RETVAL_FALSE;
332 : } else {
333 1 : REPLACE_ZVAL_VALUE(&out_message, tmp, 0);
334 : }
335 2 : FREE_ZVAL(tmp);
336 2 : PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
337 : } else {
338 0 : ZVAL_STRINGL(out_message, messagebuffer->mtext, result, 1);
339 : }
340 0 : } else if (zerrcode) {
341 0 : ZVAL_LONG(zerrcode, errno);
342 : }
343 2 : efree(messagebuffer);
344 : }
345 : /* }}} */
346 :
347 : /* {{{ proto bool msg_send(resource queue, int msgtype, mixed message [, bool serialize=true [, bool blocking=true [, int errorcode]]])
348 : Send a message of type msgtype (must be > 0) to a message queue */
349 : PHP_FUNCTION(msg_send)
350 2 : {
351 2 : zval *message, *queue, *zerror=NULL;
352 : long msgtype;
353 2 : zend_bool do_serialize = 1, blocking = 1;
354 2 : sysvmsg_queue_t * mq = NULL;
355 2 : struct php_msgbuf * messagebuffer = NULL; /* buffer to transmit */
356 : int result;
357 2 : int message_len = 0;
358 :
359 2 : RETVAL_FALSE;
360 :
361 2 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rlz|bbz",
362 : &queue, &msgtype, &message, &do_serialize, &blocking, &zerror) == FAILURE) {
363 0 : return;
364 : }
365 :
366 2 : ZEND_FETCH_RESOURCE(mq, sysvmsg_queue_t*, &queue, -1, "sysvmsg queue", le_sysvmsg);
367 :
368 2 : if (do_serialize) {
369 1 : smart_str msg_var = {0};
370 : php_serialize_data_t var_hash;
371 :
372 1 : PHP_VAR_SERIALIZE_INIT(var_hash);
373 1 : php_var_serialize(&msg_var, &message, &var_hash TSRMLS_CC);
374 1 : PHP_VAR_SERIALIZE_DESTROY(var_hash);
375 :
376 : /* NB: php_msgbuf is 1 char bigger than a long, so there is no need to
377 : * allocate the extra byte. */
378 1 : messagebuffer = safe_emalloc(msg_var.len, 1, sizeof(struct php_msgbuf));
379 1 : memcpy(messagebuffer->mtext, msg_var.c, msg_var.len + 1);
380 1 : message_len = msg_var.len;
381 1 : smart_str_free(&msg_var);
382 : } else {
383 : char *p;
384 1 : switch (Z_TYPE_P(message)) {
385 : case IS_STRING:
386 1 : p = Z_STRVAL_P(message);
387 1 : message_len = Z_STRLEN_P(message);
388 1 : break;
389 :
390 : case IS_LONG:
391 : case IS_BOOL:
392 0 : message_len = spprintf(&p, 0, "%ld", Z_LVAL_P(message));
393 0 : break;
394 :
395 : case IS_DOUBLE:
396 0 : message_len = spprintf(&p, 0, "%F", Z_DVAL_P(message));
397 0 : break;
398 :
399 : default:
400 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Message parameter must be either a string or a number.");
401 0 : RETURN_FALSE;
402 : }
403 :
404 1 : messagebuffer = safe_emalloc(message_len, 1, sizeof(struct php_msgbuf));
405 1 : memcpy(messagebuffer->mtext, p, message_len + 1);
406 :
407 1 : if (Z_TYPE_P(message) != IS_STRING) {
408 0 : efree(p);
409 : }
410 : }
411 :
412 : /* set the message type */
413 2 : messagebuffer->mtype = msgtype;
414 :
415 2 : result = msgsnd(mq->id, messagebuffer, message_len, blocking ? 0 : IPC_NOWAIT);
416 :
417 2 : efree(messagebuffer);
418 :
419 2 : if (result == -1) {
420 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "msgsnd failed: %s", strerror(errno));
421 0 : if (zerror) {
422 0 : ZVAL_LONG(zerror, errno);
423 : }
424 : } else {
425 2 : RETVAL_TRUE;
426 : }
427 : }
428 : /* }}} */
429 :
430 : /*
431 : * Local variables:
432 : * tab-width: 4
433 : * c-basic-offset: 4
434 : * End:
435 : * vim600: noet sw=4 ts=4 tw=78 fdm=marker
436 : * vim<600: noet sw=4 ts=4 tw=78
437 : */
|