You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

402 lines
12 KiB

  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP version 4.0 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2002 The PHP Group |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 2.02 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available at through the world-wide-web at |
  10. | http://www.php.net/license/2_02.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: Wez Furlong <wez@thebrainroom.com |
  16. +----------------------------------------------------------------------+
  17. */
  18. /* $Id$ */
  19. #ifdef HAVE_CONFIG_H
  20. #include "config.h"
  21. #endif
  22. #include "php.h"
  23. #include "php_globals.h"
  24. #include "php_ini.h"
  25. #include "ext/standard/info.h"
  26. #include "php_sysvmsg.h"
  27. #include "ext/standard/php_var.h"
  28. #include "ext/standard/php_smart_str.h"
  29. /* In order to detect MSG_EXCEPT use at run time; we have no way
  30. * of knowing what the bit definitions are, so we can't just define
  31. * out own MSG_EXCEPT value. */
  32. #define PHP_MSG_IPC_NOWAIT 1
  33. #define PHP_MSG_NOERROR 2
  34. #define PHP_MSG_EXCEPT 4
  35. /* True global resources - no need for thread safety here */
  36. static int le_sysvmsg;
  37. static unsigned char sixth_arg_force_ref[] = { 6, BYREF_NONE, BYREF_NONE, BYREF_NONE, BYREF_NONE, BYREF_NONE, BYREF_FORCE };
  38. static unsigned char msg_receive_args_force_ref[] = { 8, BYREF_NONE, BYREF_NONE, BYREF_FORCE,
  39. BYREF_NONE, BYREF_FORCE, BYREF_NONE, BYREF_NONE, BYREF_FORCE };
  40. /* {{{ sysvmsg_functions[]
  41. *
  42. * Every user visible function must have an entry in sysvmsg_functions[].
  43. */
  44. function_entry sysvmsg_functions[] = {
  45. PHP_FE(msg_get_queue, NULL)
  46. PHP_FE(msg_send, sixth_arg_force_ref)
  47. PHP_FE(msg_receive, msg_receive_args_force_ref)
  48. PHP_FE(msg_remove_queue, NULL)
  49. PHP_FE(msg_stat_queue, NULL)
  50. PHP_FE(msg_set_queue, NULL)
  51. {NULL, NULL, NULL} /* Must be the last line in sysvmsg_functions[] */
  52. };
  53. /* }}} */
  54. /* {{{ sysvmsg_module_entry
  55. */
  56. zend_module_entry sysvmsg_module_entry = {
  57. STANDARD_MODULE_HEADER,
  58. "sysvmsg",
  59. sysvmsg_functions,
  60. PHP_MINIT(sysvmsg),
  61. PHP_MSHUTDOWN(sysvmsg),
  62. NULL,
  63. NULL,
  64. PHP_MINFO(sysvmsg),
  65. NO_VERSION_YET,
  66. STANDARD_MODULE_PROPERTIES
  67. };
  68. /* }}} */
  69. #ifdef COMPILE_DL_SYSVMSG
  70. ZEND_GET_MODULE(sysvmsg)
  71. #endif
  72. /* {{{ PHP_INI
  73. */
  74. /* Remove comments and fill if you need to have entries in php.ini
  75. PHP_INI_BEGIN()
  76. STD_PHP_INI_ENTRY("sysvmsg.value", "42", PHP_INI_ALL, OnUpdateInt, global_value, zend_sysvmsg_globals, sysvmsg_globals)
  77. STD_PHP_INI_ENTRY("sysvmsg.string", "foobar", PHP_INI_ALL, OnUpdateString, global_string, zend_sysvmsg_globals, sysvmsg_globals)
  78. PHP_INI_END()
  79. */
  80. /* }}} */
  81. static void sysvmsg_release(zend_rsrc_list_entry *rsrc)
  82. {
  83. sysvmsg_queue_t * mq = (sysvmsg_queue_t*)rsrc->ptr;
  84. efree(mq);
  85. }
  86. /* {{{ PHP_MINIT_FUNCTION
  87. */
  88. PHP_MINIT_FUNCTION(sysvmsg)
  89. {
  90. le_sysvmsg = zend_register_list_destructors_ex(sysvmsg_release, NULL, "sysvmsg queue", module_number);
  91. REGISTER_LONG_CONSTANT("MSG_IPC_NOWAIT", PHP_MSG_IPC_NOWAIT, CONST_PERSISTENT|CONST_CS);
  92. REGISTER_LONG_CONSTANT("MSG_NOERROR", PHP_MSG_NOERROR, CONST_PERSISTENT|CONST_CS);
  93. REGISTER_LONG_CONSTANT("MSG_EXCEPT", PHP_MSG_EXCEPT, CONST_PERSISTENT|CONST_CS);
  94. return SUCCESS;
  95. }
  96. /* }}} */
  97. /* {{{ PHP_MSHUTDOWN_FUNCTION
  98. */
  99. PHP_MSHUTDOWN_FUNCTION(sysvmsg)
  100. {
  101. return SUCCESS;
  102. }
  103. /* }}} */
  104. /* {{{ PHP_MINFO_FUNCTION
  105. */
  106. PHP_MINFO_FUNCTION(sysvmsg)
  107. {
  108. php_info_print_table_start();
  109. php_info_print_table_header(2, "sysvmsg support", "enabled");
  110. php_info_print_table_row(2, "Revision", "$Revision$");
  111. php_info_print_table_end();
  112. }
  113. /* }}} */
  114. /* {{{ proto array msg_set_queue(resource queue, array data)
  115. Set information for a message queue */
  116. PHP_FUNCTION(msg_set_queue)
  117. {
  118. zval *queue, *data;
  119. sysvmsg_queue_t *mq = NULL;
  120. struct msqid_ds stat;
  121. RETVAL_FALSE;
  122. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ra", &queue, &data) == FAILURE)
  123. return;
  124. ZEND_FETCH_RESOURCE(mq, sysvmsg_queue_t *, &queue, -1, "sysvmsg queue", le_sysvmsg);
  125. if (msgctl(mq->id, IPC_STAT, &stat) == 0) {
  126. zval **item;
  127. /* now pull out members of data and set them in the stat buffer */
  128. if (zend_hash_find(Z_ARRVAL_P(data), "msg_perm.uid",
  129. sizeof("msg_perm.uid"), (void**)&item) == SUCCESS) {
  130. convert_to_long_ex(item);
  131. stat.msg_perm.uid = Z_LVAL_PP(item);
  132. }
  133. if (zend_hash_find(Z_ARRVAL_P(data), "msg_perm.gid",
  134. sizeof("msg_perm.gid"), (void**)&item) == SUCCESS) {
  135. convert_to_long_ex(item);
  136. stat.msg_perm.gid = Z_LVAL_PP(item);
  137. }
  138. if (zend_hash_find(Z_ARRVAL_P(data), "msg_perm.mode",
  139. sizeof("msg_perm.mode"), (void**)&item) == SUCCESS) {
  140. convert_to_long_ex(item);
  141. stat.msg_perm.mode = Z_LVAL_PP(item);
  142. }
  143. if (zend_hash_find(Z_ARRVAL_P(data), "msg_qbytes",
  144. sizeof("msg_qbytes"), (void**)&item) == SUCCESS) {
  145. convert_to_long_ex(item);
  146. stat.msg_qbytes = Z_LVAL_PP(item);
  147. }
  148. if (msgctl(mq->id, IPC_SET, &stat) == 0) {
  149. RETVAL_TRUE;
  150. }
  151. }
  152. }
  153. /* }}} */
  154. /* {{{ proto array msg_stat_queue(resource queue)
  155. Returns information about a message queue */
  156. PHP_FUNCTION(msg_stat_queue)
  157. {
  158. zval *queue;
  159. sysvmsg_queue_t *mq = NULL;
  160. struct msqid_ds stat;
  161. RETVAL_FALSE;
  162. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &queue) == FAILURE)
  163. return;
  164. ZEND_FETCH_RESOURCE(mq, sysvmsg_queue_t *, &queue, -1, "sysvmsg queue", le_sysvmsg);
  165. if (msgctl(mq->id, IPC_STAT, &stat) == 0) {
  166. array_init(return_value);
  167. add_assoc_long(return_value, "msg_perm.uid", stat.msg_perm.uid);
  168. add_assoc_long(return_value, "msg_perm.gid", stat.msg_perm.gid);
  169. add_assoc_long(return_value, "msg_perm.mode", stat.msg_perm.mode);
  170. add_assoc_long(return_value, "msg_stime", stat.msg_stime);
  171. add_assoc_long(return_value, "msg_rtime", stat.msg_rtime);
  172. add_assoc_long(return_value, "msg_ctime", stat.msg_ctime);
  173. add_assoc_long(return_value, "msg_qnum", stat.msg_qnum);
  174. add_assoc_long(return_value, "msg_qbytes", stat.msg_qbytes);
  175. add_assoc_long(return_value, "msg_lspid", stat.msg_lspid);
  176. add_assoc_long(return_value, "msg_lrpid", stat.msg_lrpid);
  177. }
  178. }
  179. /* }}} */
  180. /* {{{ proto resource msg_get_queue(long key [, long perms])
  181. Attach to a message queue */
  182. PHP_FUNCTION(msg_get_queue)
  183. {
  184. long key;
  185. long perms = 0666;
  186. sysvmsg_queue_t *mq;
  187. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|l", &key, &perms) == FAILURE) {
  188. return;
  189. }
  190. mq = (sysvmsg_queue_t *)emalloc(sizeof(sysvmsg_queue_t));
  191. mq->key = key;
  192. mq->id = msgget(key, 0);
  193. if (mq->id < 0) {
  194. /* doesn't already exist; create it */
  195. mq->id = msgget(key, IPC_CREAT|IPC_EXCL|perms);
  196. if (mq->id < 0) {
  197. zend_error(E_WARNING, "%s: msgget() failed for key 0x%x: %s",
  198. get_active_function_name(TSRMLS_C), key, strerror(errno));
  199. efree(mq);
  200. RETURN_FALSE;
  201. }
  202. }
  203. RETVAL_RESOURCE(zend_list_insert(mq, le_sysvmsg));
  204. }
  205. /* }}} */
  206. /* {{{ proto bool msg_remove_queue(resource queue)
  207. Destroy the queue */
  208. PHP_FUNCTION(msg_remove_queue)
  209. {
  210. zval *queue;
  211. sysvmsg_queue_t *mq = NULL;
  212. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &queue) == FAILURE)
  213. return;
  214. ZEND_FETCH_RESOURCE(mq, sysvmsg_queue_t *, &queue, -1, "sysvmsg queue", le_sysvmsg);
  215. if (msgctl(mq->id, IPC_RMID, NULL) == 0) {
  216. RETVAL_TRUE;
  217. } else {
  218. RETVAL_FALSE;
  219. }
  220. }
  221. /* }}} */
  222. /* {{{ proto mixed msg_receive(resource queue, long desiredmsgtype, long &msgtype, long maxsize, mixed message [[, bool unserialize=true][, long flags=0[, long errorcode]]]
  223. Send a message of type msgtype (must be > 0) to a message queue */
  224. PHP_FUNCTION(msg_receive)
  225. {
  226. zval *out_message, *queue, *out_msgtype, *zerrcode = NULL;
  227. long desiredmsgtype, maxsize, flags = 0;
  228. long realflags = 0;
  229. zend_bool do_unserialize = 1;
  230. sysvmsg_queue_t *mq = NULL;
  231. struct msgbuf *messagebuffer = NULL; /* buffer to transmit */
  232. int result;
  233. RETVAL_FALSE;
  234. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rlzlz|blz",
  235. &queue, &desiredmsgtype, &out_msgtype, &maxsize,
  236. &out_message, &do_unserialize, &flags, &zerrcode) == FAILURE)
  237. return;
  238. if (flags != 0) {
  239. if (flags & PHP_MSG_EXCEPT) {
  240. #ifndef MSG_EXCEPT
  241. php_error_docref(NULL TSRMLS_CC, E_WARNING, "MSG_EXCEPT is not supported on your system");
  242. RETURN_FALSE;
  243. #else
  244. realflags |= MSG_EXCEPT;
  245. #endif
  246. }
  247. if (flags & PHP_MSG_NOERROR)
  248. realflags |= MSG_NOERROR;
  249. if (flags & PHP_MSG_IPC_NOWAIT)
  250. realflags |= IPC_NOWAIT;
  251. }
  252. ZEND_FETCH_RESOURCE(mq, sysvmsg_queue_t *, &queue, -1, "sysvmsg queue", le_sysvmsg);
  253. messagebuffer = (struct msgbuf*)emalloc(sizeof(struct msgbuf) + maxsize);
  254. result = msgrcv(mq->id, messagebuffer, maxsize, desiredmsgtype, realflags);
  255. zval_dtor(out_msgtype);
  256. zval_dtor(out_message);
  257. ZVAL_LONG(out_msgtype, 0);
  258. ZVAL_FALSE(out_message);
  259. if (zerrcode) {
  260. zval_dtor(zerrcode);
  261. ZVAL_LONG(zerrcode, 0);
  262. }
  263. if (result >= 0) {
  264. /* got it! */
  265. ZVAL_LONG(out_msgtype, messagebuffer->mtype);
  266. if (do_unserialize) {
  267. php_unserialize_data_t var_hash;
  268. zval *tmp = NULL;
  269. const char *p = (const char*)messagebuffer->mtext;
  270. MAKE_STD_ZVAL(tmp);
  271. PHP_VAR_UNSERIALIZE_INIT(var_hash);
  272. if (!php_var_unserialize(&tmp, &p, p + result, &var_hash TSRMLS_CC)) {
  273. zend_error(E_WARNING, "%s(): message corrupted", get_active_function_name(TSRMLS_C));
  274. RETVAL_FALSE;
  275. }
  276. REPLACE_ZVAL_VALUE(&out_message, tmp, 0);
  277. FREE_ZVAL(tmp);
  278. PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
  279. } else {
  280. ZVAL_STRINGL(out_message, messagebuffer->mtext, result, 1);
  281. }
  282. RETVAL_TRUE;
  283. } else if (zerrcode) {
  284. ZVAL_LONG(zerrcode, errno);
  285. }
  286. efree(messagebuffer);
  287. }
  288. /* }}} */
  289. /* {{{ proto bool msg_send(resource queue, long msgtype, mixed message [[, bool serialize=true][, bool blocking=true][, long errorcode]])
  290. Send a message of type msgtype (must be > 0) to a message queue */
  291. PHP_FUNCTION(msg_send)
  292. {
  293. zval *message, *queue, *zerror=NULL;
  294. long msgtype;
  295. zend_bool do_serialize = 1, blocking = 1;
  296. sysvmsg_queue_t * mq = NULL;
  297. struct msgbuf * messagebuffer = NULL; /* buffer to transmit */
  298. int result;
  299. int message_len = 0;
  300. RETVAL_FALSE;
  301. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rlz|bbz",
  302. &queue, &msgtype, &message, &do_serialize, &blocking, &zerror) == FAILURE)
  303. return;
  304. ZEND_FETCH_RESOURCE(mq, sysvmsg_queue_t*, &queue, -1, "sysvmsg queue", le_sysvmsg);
  305. if (do_serialize) {
  306. smart_str msg_var = {0};
  307. php_serialize_data_t var_hash;
  308. PHP_VAR_SERIALIZE_INIT(var_hash);
  309. php_var_serialize(&msg_var, &message, &var_hash TSRMLS_CC);
  310. PHP_VAR_SERIALIZE_DESTROY(var_hash);
  311. /* NB: msgbuf is 1 char bigger than a long, so there is no need to
  312. * allocate the extra byte. */
  313. messagebuffer = emalloc(sizeof(struct msgbuf) + msg_var.len);
  314. memcpy(messagebuffer->mtext, msg_var.c, msg_var.len + 1);
  315. message_len = msg_var.len;
  316. smart_str_free(&msg_var);
  317. } else {
  318. convert_to_string_ex(&message);
  319. messagebuffer = emalloc(sizeof(struct msgbuf) + Z_STRLEN_P(message));
  320. memcpy(messagebuffer->mtext, Z_STRVAL_P(message), Z_STRLEN_P(message) + 1);
  321. message_len = Z_STRLEN_P(message);
  322. }
  323. /* set the message type */
  324. messagebuffer->mtype = msgtype;
  325. result = msgsnd(mq->id, messagebuffer, message_len, blocking ? 0 : IPC_NOWAIT);
  326. efree(messagebuffer);
  327. if (result == -1) {
  328. zend_error(E_WARNING, "%s(): msgsnd failed: %s",
  329. get_active_function_name(TSRMLS_C), strerror(errno));
  330. if (zerror) {
  331. ZVAL_LONG(zerror, errno);
  332. }
  333. } else {
  334. RETVAL_TRUE;
  335. }
  336. }
  337. /* }}} */
  338. /*
  339. * Local variables:
  340. * tab-width: 4
  341. * c-basic-offset: 4
  342. * End:
  343. * vim600: noet sw=4 ts=4 tw=78 fdm=marker
  344. * vim<600: noet sw=4 ts=4 tw=78
  345. */