shmop.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP version 7 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 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. | https://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. #ifdef HAVE_CONFIG_H
  20. #include "config.h"
  21. #endif
  22. #include "php.h"
  23. #include "php_ini.h"
  24. #include "php_shmop.h"
  25. #include "shmop_arginfo.h"
  26. # ifndef PHP_WIN32
  27. # include <sys/ipc.h>
  28. # include <sys/shm.h>
  29. #else
  30. #include "tsrm_win32.h"
  31. #endif
  32. #ifdef HAVE_SHMOP
  33. #include "ext/standard/info.h"
  34. /* {{{ shmop_module_entry */
  35. zend_module_entry shmop_module_entry = {
  36. STANDARD_MODULE_HEADER,
  37. "shmop",
  38. ext_functions,
  39. PHP_MINIT(shmop),
  40. NULL,
  41. NULL,
  42. NULL,
  43. PHP_MINFO(shmop),
  44. PHP_SHMOP_VERSION,
  45. STANDARD_MODULE_PROPERTIES
  46. };
  47. /* }}} */
  48. #ifdef COMPILE_DL_SHMOP
  49. ZEND_GET_MODULE(shmop)
  50. #endif
  51. typedef struct php_shmop
  52. {
  53. int shmid;
  54. key_t key;
  55. int shmflg;
  56. int shmatflg;
  57. char *addr;
  58. zend_long size;
  59. zend_object std;
  60. } php_shmop;
  61. zend_class_entry *shmop_ce;
  62. static zend_object_handlers shmop_object_handlers;
  63. static inline php_shmop *shmop_from_obj(zend_object *obj)
  64. {
  65. return (php_shmop *)((char *)(obj) - XtOffsetOf(php_shmop, std));
  66. }
  67. #define Z_SHMOP_P(zv) shmop_from_obj(Z_OBJ_P(zv))
  68. static zend_object *shmop_create_object(zend_class_entry *class_type)
  69. {
  70. php_shmop *intern = zend_object_alloc(sizeof(php_shmop), class_type);
  71. zend_object_std_init(&intern->std, class_type);
  72. object_properties_init(&intern->std, class_type);
  73. intern->std.handlers = &shmop_object_handlers;
  74. return &intern->std;
  75. }
  76. static zend_function *shmop_get_constructor(zend_object *object)
  77. {
  78. zend_throw_error(NULL, "Cannot directly construct Shmop, use shmop_open() instead");
  79. return NULL;
  80. }
  81. static void shmop_free_obj(zend_object *object)
  82. {
  83. php_shmop *shmop = shmop_from_obj(object);
  84. shmdt(shmop->addr);
  85. zend_object_std_dtor(&shmop->std);
  86. }
  87. /* {{{ PHP_MINIT_FUNCTION */
  88. PHP_MINIT_FUNCTION(shmop)
  89. {
  90. shmop_ce = register_class_Shmop();
  91. shmop_ce->create_object = shmop_create_object;
  92. memcpy(&shmop_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
  93. shmop_object_handlers.offset = XtOffsetOf(php_shmop, std);
  94. shmop_object_handlers.free_obj = shmop_free_obj;
  95. shmop_object_handlers.get_constructor = shmop_get_constructor;
  96. shmop_object_handlers.clone_obj = NULL;
  97. shmop_object_handlers.compare = zend_objects_not_comparable;
  98. return SUCCESS;
  99. }
  100. /* }}} */
  101. /* {{{ PHP_MINFO_FUNCTION */
  102. PHP_MINFO_FUNCTION(shmop)
  103. {
  104. php_info_print_table_start();
  105. php_info_print_table_row(2, "shmop support", "enabled");
  106. php_info_print_table_end();
  107. }
  108. /* }}} */
  109. /* {{{ gets and attaches a shared memory segment */
  110. PHP_FUNCTION(shmop_open)
  111. {
  112. zend_long key, mode, size;
  113. php_shmop *shmop;
  114. struct shmid_ds shm;
  115. char *flags;
  116. size_t flags_len;
  117. if (zend_parse_parameters(ZEND_NUM_ARGS(), "lsll", &key, &flags, &flags_len, &mode, &size) == FAILURE) {
  118. RETURN_THROWS();
  119. }
  120. if (flags_len != 1) {
  121. zend_argument_value_error(2, "must be a valid access mode");
  122. RETURN_THROWS();
  123. }
  124. object_init_ex(return_value, shmop_ce);
  125. shmop = Z_SHMOP_P(return_value);
  126. shmop->key = key;
  127. shmop->shmflg |= mode;
  128. switch (flags[0])
  129. {
  130. case 'a':
  131. shmop->shmatflg |= SHM_RDONLY;
  132. break;
  133. case 'c':
  134. shmop->shmflg |= IPC_CREAT;
  135. shmop->size = size;
  136. break;
  137. case 'n':
  138. shmop->shmflg |= (IPC_CREAT | IPC_EXCL);
  139. shmop->size = size;
  140. break;
  141. case 'w':
  142. /* noop
  143. shm segment is being opened for read & write
  144. will fail if segment does not exist
  145. */
  146. break;
  147. default:
  148. zend_argument_value_error(2, "must be a valid access mode");
  149. goto err;
  150. }
  151. if (shmop->shmflg & IPC_CREAT && shmop->size < 1) {
  152. zend_argument_value_error(4, "must be greater than 0 for the \"c\" and \"n\" access modes");
  153. goto err;
  154. }
  155. shmop->shmid = shmget(shmop->key, shmop->size, shmop->shmflg);
  156. if (shmop->shmid == -1) {
  157. php_error_docref(NULL, E_WARNING, "Unable to attach or create shared memory segment \"%s\"", strerror(errno));
  158. goto err;
  159. }
  160. if (shmctl(shmop->shmid, IPC_STAT, &shm)) {
  161. /* please do not add coverage here: the segment would be leaked and impossible to delete via php */
  162. php_error_docref(NULL, E_WARNING, "Unable to get shared memory segment information \"%s\"", strerror(errno));
  163. goto err;
  164. }
  165. if (shm.shm_segsz > ZEND_LONG_MAX) {
  166. zend_argument_value_error(4, "is too large");
  167. goto err;
  168. }
  169. shmop->addr = shmat(shmop->shmid, 0, shmop->shmatflg);
  170. if (shmop->addr == (char*) -1) {
  171. php_error_docref(NULL, E_WARNING, "Unable to attach to shared memory segment \"%s\"", strerror(errno));
  172. goto err;
  173. }
  174. shmop->size = shm.shm_segsz;
  175. return;
  176. err:
  177. zend_object_release(Z_OBJ_P(return_value));
  178. RETURN_FALSE;
  179. }
  180. /* }}} */
  181. /* {{{ reads from a shm segment */
  182. PHP_FUNCTION(shmop_read)
  183. {
  184. zval *shmid;
  185. zend_long start, count;
  186. php_shmop *shmop;
  187. char *startaddr;
  188. int bytes;
  189. zend_string *return_string;
  190. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Oll", &shmid, shmop_ce, &start, &count) == FAILURE) {
  191. RETURN_THROWS();
  192. }
  193. shmop = Z_SHMOP_P(shmid);
  194. if (start < 0 || start > shmop->size) {
  195. zend_argument_value_error(2, "must be between 0 and the segment size");
  196. RETURN_THROWS();
  197. }
  198. if (count < 0 || start > (ZEND_LONG_MAX - count) || start + count > shmop->size) {
  199. zend_argument_value_error(3, "is out of range");
  200. RETURN_THROWS();
  201. }
  202. startaddr = shmop->addr + start;
  203. bytes = count ? count : shmop->size - start;
  204. return_string = zend_string_init(startaddr, bytes, 0);
  205. RETURN_NEW_STR(return_string);
  206. }
  207. /* }}} */
  208. /* {{{ used to close a shared memory segment; now a NOP */
  209. PHP_FUNCTION(shmop_close)
  210. {
  211. zval *shmid;
  212. if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &shmid, shmop_ce) == FAILURE) {
  213. RETURN_THROWS();
  214. }
  215. }
  216. /* }}} */
  217. /* {{{ returns the shm size */
  218. PHP_FUNCTION(shmop_size)
  219. {
  220. zval *shmid;
  221. php_shmop *shmop;
  222. if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &shmid, shmop_ce) == FAILURE) {
  223. RETURN_THROWS();
  224. }
  225. shmop = Z_SHMOP_P(shmid);
  226. RETURN_LONG(shmop->size);
  227. }
  228. /* }}} */
  229. /* {{{ writes to a shared memory segment */
  230. PHP_FUNCTION(shmop_write)
  231. {
  232. php_shmop *shmop;
  233. zend_long writesize;
  234. zend_long offset;
  235. zend_string *data;
  236. zval *shmid;
  237. if (zend_parse_parameters(ZEND_NUM_ARGS(), "OSl", &shmid, shmop_ce, &data, &offset) == FAILURE) {
  238. RETURN_THROWS();
  239. }
  240. shmop = Z_SHMOP_P(shmid);
  241. if ((shmop->shmatflg & SHM_RDONLY) == SHM_RDONLY) {
  242. zend_throw_error(NULL, "Read-only segment cannot be written");
  243. RETURN_THROWS();
  244. }
  245. if (offset < 0 || offset > shmop->size) {
  246. zend_argument_value_error(3, "is out of range");
  247. RETURN_THROWS();
  248. }
  249. writesize = ((zend_long)ZSTR_LEN(data) < shmop->size - offset) ? (zend_long)ZSTR_LEN(data) : shmop->size - offset;
  250. memcpy(shmop->addr + offset, ZSTR_VAL(data), writesize);
  251. RETURN_LONG(writesize);
  252. }
  253. /* }}} */
  254. /* {{{ mark segment for deletion */
  255. PHP_FUNCTION(shmop_delete)
  256. {
  257. zval *shmid;
  258. php_shmop *shmop;
  259. if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &shmid, shmop_ce) == FAILURE) {
  260. RETURN_THROWS();
  261. }
  262. shmop = Z_SHMOP_P(shmid);
  263. if (shmctl(shmop->shmid, IPC_RMID, NULL)) {
  264. php_error_docref(NULL, E_WARNING, "Can't mark segment for deletion (are you the owner?)");
  265. RETURN_FALSE;
  266. }
  267. RETURN_TRUE;
  268. }
  269. /* }}} */
  270. #endif /* HAVE_SHMOP */