root/ext/sysvmsg/sysvmsg.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ZEND_GET_MODULE
  2. PHP_MINIT_FUNCTION
  3. PHP_MINFO_FUNCTION
  4. PHP_FUNCTION
  5. PHP_FUNCTION
  6. PHP_FUNCTION
  7. PHP_FUNCTION
  8. PHP_FUNCTION
  9. PHP_FUNCTION
  10. PHP_FUNCTION

   1 /*
   2   +----------------------------------------------------------------------+
   3   | PHP Version 7                                                        |
   4   +----------------------------------------------------------------------+
   5   | Copyright (c) 1997-2016 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: b291daed03ee2339361df6b8cd4d9f5eb4c76387 $ */
  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 "zend_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 /* {{{ arginfo */
  43 ZEND_BEGIN_ARG_INFO_EX(arginfo_msg_get_queue, 0, 0, 1)
  44         ZEND_ARG_INFO(0, key)
  45         ZEND_ARG_INFO(0, perms)
  46 ZEND_END_ARG_INFO()
  47 
  48 ZEND_BEGIN_ARG_INFO_EX(arginfo_msg_send, 0, 0, 3)
  49         ZEND_ARG_INFO(0, queue)
  50         ZEND_ARG_INFO(0, msgtype)
  51         ZEND_ARG_INFO(0, message)
  52         ZEND_ARG_INFO(0, serialize)
  53         ZEND_ARG_INFO(0, blocking)
  54         ZEND_ARG_INFO(1, errorcode)
  55 ZEND_END_ARG_INFO()
  56 
  57 ZEND_BEGIN_ARG_INFO_EX(arginfo_msg_receive, 0, 0, 5)
  58         ZEND_ARG_INFO(0, queue)
  59         ZEND_ARG_INFO(0, desiredmsgtype)
  60         ZEND_ARG_INFO(1, msgtype)
  61         ZEND_ARG_INFO(0, maxsize)
  62         ZEND_ARG_INFO(1, message)
  63         ZEND_ARG_INFO(0, unserialize)
  64         ZEND_ARG_INFO(0, flags)
  65         ZEND_ARG_INFO(1, errorcode)
  66 ZEND_END_ARG_INFO()
  67 
  68 ZEND_BEGIN_ARG_INFO_EX(arginfo_msg_remove_queue, 0, 0, 1)
  69         ZEND_ARG_INFO(0, queue)
  70 ZEND_END_ARG_INFO()
  71 
  72 ZEND_BEGIN_ARG_INFO_EX(arginfo_msg_stat_queue, 0, 0, 1)
  73         ZEND_ARG_INFO(0, queue)
  74 ZEND_END_ARG_INFO()
  75 
  76 ZEND_BEGIN_ARG_INFO_EX(arginfo_msg_set_queue, 0, 0, 2)
  77         ZEND_ARG_INFO(0, queue)
  78         ZEND_ARG_INFO(0, data)
  79 ZEND_END_ARG_INFO()
  80 
  81 ZEND_BEGIN_ARG_INFO_EX(arginfo_msg_queue_exists, 0, 0, 1)
  82         ZEND_ARG_INFO(0, key)
  83 ZEND_END_ARG_INFO()
  84 /* }}} */
  85 
  86 /* {{{ sysvmsg_functions[]
  87  *
  88  * Every user visible function must have an entry in sysvmsg_functions[].
  89  */
  90 const zend_function_entry sysvmsg_functions[] = {
  91         PHP_FE(msg_get_queue,                           arginfo_msg_get_queue)
  92         PHP_FE(msg_send,                                        arginfo_msg_send)
  93         PHP_FE(msg_receive,                                     arginfo_msg_receive)
  94         PHP_FE(msg_remove_queue,                        arginfo_msg_remove_queue)
  95         PHP_FE(msg_stat_queue,                          arginfo_msg_stat_queue)
  96         PHP_FE(msg_set_queue,                           arginfo_msg_set_queue)
  97         PHP_FE(msg_queue_exists,                        arginfo_msg_queue_exists)
  98         PHP_FE_END
  99 };
 100 /* }}} */
 101 
 102 /* {{{ sysvmsg_module_entry
 103  */
 104 zend_module_entry sysvmsg_module_entry = {
 105         STANDARD_MODULE_HEADER,
 106         "sysvmsg",
 107         sysvmsg_functions,
 108         PHP_MINIT(sysvmsg),
 109         NULL,
 110         NULL,
 111         NULL,
 112         PHP_MINFO(sysvmsg),
 113         PHP_SYSVMSG_VERSION,
 114         STANDARD_MODULE_PROPERTIES
 115 };
 116 /* }}} */
 117 
 118 #ifdef COMPILE_DL_SYSVMSG
 119 ZEND_GET_MODULE(sysvmsg)
 120 #endif
 121 
 122 static void sysvmsg_release(zend_resource *rsrc)
 123 {
 124         sysvmsg_queue_t *mq = (sysvmsg_queue_t *) rsrc->ptr;
 125         efree(mq);
 126 }
 127 
 128 /* {{{ PHP_MINIT_FUNCTION
 129  */
 130 PHP_MINIT_FUNCTION(sysvmsg)
 131 {
 132         le_sysvmsg = zend_register_list_destructors_ex(sysvmsg_release, NULL, "sysvmsg queue", module_number);
 133         REGISTER_LONG_CONSTANT("MSG_IPC_NOWAIT", PHP_MSG_IPC_NOWAIT, CONST_PERSISTENT|CONST_CS);
 134         REGISTER_LONG_CONSTANT("MSG_EAGAIN",     EAGAIN,             CONST_PERSISTENT|CONST_CS);
 135         REGISTER_LONG_CONSTANT("MSG_ENOMSG",     ENOMSG,             CONST_PERSISTENT|CONST_CS);
 136         REGISTER_LONG_CONSTANT("MSG_NOERROR",    PHP_MSG_NOERROR,    CONST_PERSISTENT|CONST_CS);
 137         REGISTER_LONG_CONSTANT("MSG_EXCEPT",     PHP_MSG_EXCEPT,     CONST_PERSISTENT|CONST_CS);
 138         return SUCCESS;
 139 }
 140 /* }}} */
 141 
 142 /* {{{ PHP_MINFO_FUNCTION
 143  */
 144 PHP_MINFO_FUNCTION(sysvmsg)
 145 {
 146         php_info_print_table_start();
 147         php_info_print_table_row(2, "sysvmsg support", "enabled");
 148         php_info_print_table_row(2, "Revision", "$Id: b291daed03ee2339361df6b8cd4d9f5eb4c76387 $");
 149         php_info_print_table_end();
 150 }
 151 /* }}} */
 152 
 153 /* {{{ proto bool msg_set_queue(resource queue, array data)
 154    Set information for a message queue */
 155 PHP_FUNCTION(msg_set_queue)
 156 {
 157         zval *queue, *data;
 158         sysvmsg_queue_t *mq = NULL;
 159         struct msqid_ds stat;
 160 
 161         RETVAL_FALSE;
 162 
 163         if (zend_parse_parameters(ZEND_NUM_ARGS(), "ra", &queue, &data) == FAILURE) {
 164                 return;
 165         }
 166 
 167         if ((mq = (sysvmsg_queue_t *)zend_fetch_resource(Z_RES_P(queue), "sysvmsg queue", le_sysvmsg)) == NULL) {
 168                 RETURN_FALSE;
 169         }
 170 
 171         if (msgctl(mq->id, IPC_STAT, &stat) == 0) {
 172                 zval *item;
 173 
 174                 /* now pull out members of data and set them in the stat buffer */
 175                 if ((item = zend_hash_str_find(Z_ARRVAL_P(data), "msg_perm.uid", sizeof("msg_perm.uid") - 1)) != NULL) {
 176                         convert_to_long_ex(item);
 177                         stat.msg_perm.uid = Z_LVAL_P(item);
 178                 }
 179                 if ((item = zend_hash_str_find(Z_ARRVAL_P(data), "msg_perm.gid", sizeof("msg_perm.gid") - 1)) != NULL) {
 180                         convert_to_long_ex(item);
 181                         stat.msg_perm.gid = Z_LVAL_P(item);
 182                 }
 183                 if ((item = zend_hash_str_find(Z_ARRVAL_P(data), "msg_perm.mode", sizeof("msg_perm.mode") - 1)) != NULL) {
 184                         convert_to_long_ex(item);
 185                         stat.msg_perm.mode = Z_LVAL_P(item);
 186                 }
 187                 if ((item = zend_hash_str_find(Z_ARRVAL_P(data), "msg_qbytes", sizeof("msg_qbytes") - 1)) != NULL) {
 188                         convert_to_long_ex(item);
 189                         stat.msg_qbytes = Z_LVAL_P(item);
 190                 }
 191                 if (msgctl(mq->id, IPC_SET, &stat) == 0) {
 192                         RETVAL_TRUE;
 193                 }
 194         }
 195 }
 196 /* }}} */
 197 
 198 /* {{{ proto array msg_stat_queue(resource queue)
 199    Returns information about a message queue */
 200 PHP_FUNCTION(msg_stat_queue)
 201 {
 202         zval *queue;
 203         sysvmsg_queue_t *mq = NULL;
 204         struct msqid_ds stat;
 205 
 206         RETVAL_FALSE;
 207 
 208         if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &queue) == FAILURE) {
 209                 return;
 210         }
 211 
 212         if ((mq = (sysvmsg_queue_t *)zend_fetch_resource(Z_RES_P(queue), "sysvmsg queue", le_sysvmsg)) == NULL) {
 213                 RETURN_FALSE;
 214         }
 215 
 216         if (msgctl(mq->id, IPC_STAT, &stat) == 0) {
 217                 array_init(return_value);
 218 
 219                 add_assoc_long(return_value, "msg_perm.uid", stat.msg_perm.uid);
 220                 add_assoc_long(return_value, "msg_perm.gid", stat.msg_perm.gid);
 221                 add_assoc_long(return_value, "msg_perm.mode", stat.msg_perm.mode);
 222                 add_assoc_long(return_value, "msg_stime",  stat.msg_stime);
 223                 add_assoc_long(return_value, "msg_rtime",  stat.msg_rtime);
 224                 add_assoc_long(return_value, "msg_ctime",  stat.msg_ctime);
 225                 add_assoc_long(return_value, "msg_qnum",   stat.msg_qnum);
 226                 add_assoc_long(return_value, "msg_qbytes", stat.msg_qbytes);
 227                 add_assoc_long(return_value, "msg_lspid",  stat.msg_lspid);
 228                 add_assoc_long(return_value, "msg_lrpid",  stat.msg_lrpid);
 229         }
 230 }
 231 /* }}} */
 232 
 233 /* {{{ proto bool msg_queue_exists(int key)
 234    Check whether a message queue exists */
 235 PHP_FUNCTION(msg_queue_exists)
 236 {
 237         zend_long key;
 238 
 239         if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &key) == FAILURE)       {
 240                 return;
 241         }
 242 
 243         if (msgget(key, 0) < 0) {
 244                 RETURN_FALSE;
 245         }
 246 
 247         RETURN_TRUE;
 248 }
 249 /* }}} */
 250 
 251 /* {{{ proto resource msg_get_queue(int key [, int perms])
 252    Attach to a message queue */
 253 PHP_FUNCTION(msg_get_queue)
 254 {
 255         zend_long key;
 256         zend_long perms = 0666;
 257         sysvmsg_queue_t *mq;
 258 
 259         if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|l", &key, &perms) == FAILURE)     {
 260                 return;
 261         }
 262 
 263         mq = (sysvmsg_queue_t *) emalloc(sizeof(sysvmsg_queue_t));
 264 
 265         mq->key = key;
 266         mq->id = msgget(key, 0);
 267         if (mq->id < 0) {
 268                 /* doesn't already exist; create it */
 269                 mq->id = msgget(key, IPC_CREAT | IPC_EXCL | perms);
 270                 if (mq->id < 0) {
 271                         php_error_docref(NULL, E_WARNING, "failed for key 0x%lx: %s", key, strerror(errno));
 272                         efree(mq);
 273                         RETURN_FALSE;
 274                 }
 275         }
 276         ZVAL_COPY_VALUE(return_value, zend_list_insert(mq, le_sysvmsg));
 277 }
 278 /* }}} */
 279 
 280 /* {{{ proto bool msg_remove_queue(resource queue)
 281    Destroy the queue */
 282 PHP_FUNCTION(msg_remove_queue)
 283 {
 284         zval *queue;
 285         sysvmsg_queue_t *mq = NULL;
 286 
 287         if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &queue) == FAILURE) {
 288                 return;
 289         }
 290 
 291         if ((mq = (sysvmsg_queue_t *)zend_fetch_resource(Z_RES_P(queue), "sysvmsg queue", le_sysvmsg)) == NULL) {
 292                 RETURN_FALSE;
 293         }
 294 
 295         if (msgctl(mq->id, IPC_RMID, NULL) == 0) {
 296                 RETVAL_TRUE;
 297         } else {
 298                 RETVAL_FALSE;
 299         }
 300 }
 301 /* }}} */
 302 
 303 /* {{{ proto mixed msg_receive(resource queue, int desiredmsgtype, int &msgtype, int maxsize, mixed message [, bool unserialize=true [, int flags=0 [, int errorcode]]])
 304    Send a message of type msgtype (must be > 0) to a message queue */
 305 PHP_FUNCTION(msg_receive)
 306 {
 307         zval *out_message, *queue, *out_msgtype, *zerrcode = NULL;
 308         zend_long desiredmsgtype, maxsize, flags = 0;
 309         zend_long realflags = 0;
 310         zend_bool do_unserialize = 1;
 311         sysvmsg_queue_t *mq = NULL;
 312         struct php_msgbuf *messagebuffer = NULL; /* buffer to transmit */
 313         int result;
 314 
 315         RETVAL_FALSE;
 316 
 317         if (zend_parse_parameters(ZEND_NUM_ARGS(), "rlz/lz/|blz/",
 318                                 &queue, &desiredmsgtype, &out_msgtype, &maxsize,
 319                                 &out_message, &do_unserialize, &flags, &zerrcode) == FAILURE) {
 320                 return;
 321         }
 322 
 323         if (maxsize <= 0) {
 324                 php_error_docref(NULL, E_WARNING, "maximum size of the message has to be greater than zero");
 325                 return;
 326         }
 327 
 328         if (flags != 0) {
 329                 if (flags & PHP_MSG_EXCEPT) {
 330 #ifndef MSG_EXCEPT
 331                         php_error_docref(NULL, E_WARNING, "MSG_EXCEPT is not supported on your system");
 332                         RETURN_FALSE;
 333 #else
 334                         realflags |= MSG_EXCEPT;
 335 #endif
 336                 }
 337                 if (flags & PHP_MSG_NOERROR) {
 338                         realflags |= MSG_NOERROR;
 339                 }
 340                 if (flags & PHP_MSG_IPC_NOWAIT) {
 341                         realflags |= IPC_NOWAIT;
 342                 }
 343         }
 344 
 345         if ((mq = (sysvmsg_queue_t *)zend_fetch_resource(Z_RES_P(queue), "sysvmsg queue", le_sysvmsg)) == NULL) {
 346                 RETURN_FALSE;
 347         }
 348 
 349         messagebuffer = (struct php_msgbuf *) safe_emalloc(maxsize, 1, sizeof(struct php_msgbuf));
 350 
 351         result = msgrcv(mq->id, messagebuffer, maxsize, desiredmsgtype, realflags);
 352 
 353         zval_dtor(out_msgtype);
 354         zval_dtor(out_message);
 355         ZVAL_LONG(out_msgtype, 0);
 356         ZVAL_FALSE(out_message);
 357 
 358         if (zerrcode) {
 359                 ZVAL_DEREF(zerrcode);
 360                 zval_dtor(zerrcode);
 361                 ZVAL_LONG(zerrcode, 0);
 362         }
 363 
 364         if (result >= 0) {
 365                 /* got it! */
 366                 ZVAL_LONG(out_msgtype, messagebuffer->mtype);
 367 
 368                 RETVAL_TRUE;
 369                 if (do_unserialize)     {
 370                         php_unserialize_data_t var_hash;
 371                         zval tmp;
 372                         const unsigned char *p = (const unsigned char *) messagebuffer->mtext;
 373 
 374                         PHP_VAR_UNSERIALIZE_INIT(var_hash);
 375                         if (!php_var_unserialize(&tmp, &p, p + result, &var_hash)) {
 376                                 php_error_docref(NULL, E_WARNING, "message corrupted");
 377                                 RETVAL_FALSE;
 378                         } else {
 379                                 ZVAL_COPY_VALUE(out_message, &tmp);
 380                         }
 381                         PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
 382                 } else {
 383                         ZVAL_STRINGL(out_message, messagebuffer->mtext, result);
 384                 }
 385         } else if (zerrcode) {
 386                 ZVAL_LONG(zerrcode, errno);
 387         }
 388         efree(messagebuffer);
 389 }
 390 /* }}} */
 391 
 392 /* {{{ proto bool msg_send(resource queue, int msgtype, mixed message [, bool serialize=true [, bool blocking=true [, int errorcode]]])
 393    Send a message of type msgtype (must be > 0) to a message queue */
 394 PHP_FUNCTION(msg_send)
 395 {
 396         zval *message, *queue, *zerror=NULL;
 397         zend_long msgtype;
 398         zend_bool do_serialize = 1, blocking = 1;
 399         sysvmsg_queue_t * mq = NULL;
 400         struct php_msgbuf * messagebuffer = NULL; /* buffer to transmit */
 401         int result;
 402         int message_len = 0;
 403 
 404         RETVAL_FALSE;
 405 
 406         if (zend_parse_parameters(ZEND_NUM_ARGS(), "rlz|bbz/",
 407                                 &queue, &msgtype, &message, &do_serialize, &blocking, &zerror) == FAILURE) {
 408                 return;
 409         }
 410 
 411         if ((mq = (sysvmsg_queue_t *)zend_fetch_resource(Z_RES_P(queue), "sysvmsg queue", le_sysvmsg)) == NULL) {
 412                 RETURN_FALSE;
 413         }
 414 
 415         if (do_serialize) {
 416                 smart_str msg_var = {0};
 417                 php_serialize_data_t var_hash;
 418 
 419                 PHP_VAR_SERIALIZE_INIT(var_hash);
 420                 php_var_serialize(&msg_var, message, &var_hash);
 421                 PHP_VAR_SERIALIZE_DESTROY(var_hash);
 422 
 423                 /* NB: php_msgbuf is 1 char bigger than a long, so there is no need to
 424                  * allocate the extra byte. */
 425                 messagebuffer = safe_emalloc(ZSTR_LEN(msg_var.s), 1, sizeof(struct php_msgbuf));
 426                 memcpy(messagebuffer->mtext, ZSTR_VAL(msg_var.s), ZSTR_LEN(msg_var.s) + 1);
 427                 message_len = ZSTR_LEN(msg_var.s);
 428                 smart_str_free(&msg_var);
 429         } else {
 430                 char *p;
 431                 switch (Z_TYPE_P(message)) {
 432                         case IS_STRING:
 433                                 p = Z_STRVAL_P(message);
 434                                 message_len = Z_STRLEN_P(message);
 435                                 break;
 436 
 437                         case IS_LONG:
 438                                 message_len = spprintf(&p, 0, "%pd", Z_LVAL_P(message));
 439                                 break;
 440                         case IS_FALSE:
 441                                 message_len = spprintf(&p, 0, "0");
 442                                 break;
 443                         case IS_TRUE:
 444                                 message_len = spprintf(&p, 0, "1");
 445                                 break;
 446                         case IS_DOUBLE:
 447                                 message_len = spprintf(&p, 0, "%F", Z_DVAL_P(message));
 448                                 break;
 449                         default:
 450                                 php_error_docref(NULL, E_WARNING, "Message parameter must be either a string or a number.");
 451                                 RETURN_FALSE;
 452                 }
 453 
 454                 messagebuffer = safe_emalloc(message_len, 1, sizeof(struct php_msgbuf));
 455                 memcpy(messagebuffer->mtext, p, message_len + 1);
 456 
 457                 if (Z_TYPE_P(message) != IS_STRING) {
 458                         efree(p);
 459                 }
 460         }
 461 
 462         /* set the message type */
 463         messagebuffer->mtype = msgtype;
 464 
 465         result = msgsnd(mq->id, messagebuffer, message_len, blocking ? 0 : IPC_NOWAIT);
 466 
 467         efree(messagebuffer);
 468 
 469         if (result == -1) {
 470                 php_error_docref(NULL, E_WARNING, "msgsnd failed: %s", strerror(errno));
 471                 if (zerror) {
 472                         ZVAL_LONG(zerror, errno);
 473                 }
 474         } else {
 475                 RETVAL_TRUE;
 476         }
 477 }
 478 /* }}} */
 479 
 480 /*
 481  * Local variables:
 482  * tab-width: 4
 483  * c-basic-offset: 4
 484  * End:
 485  * vim600: noet sw=4 ts=4 tw=78 fdm=marker
 486  * vim<600: noet sw=4 ts=4 tw=78
 487  */

/* [<][>][^][v][top][bottom][index][help] */