123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332 |
- /*
- +----------------------------------------------------------------------+
- | PHP version 7 |
- +----------------------------------------------------------------------+
- | Copyright (c) The PHP Group |
- +----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | https://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
- +----------------------------------------------------------------------+
- | Authors: Slava Poliakov <hackie@prohost.org> |
- | Ilia Alshanetsky <ilia@prohost.org> |
- +----------------------------------------------------------------------+
- */
- #ifdef HAVE_CONFIG_H
- #include "config.h"
- #endif
- #include "php.h"
- #include "php_ini.h"
- #include "php_shmop.h"
- #include "shmop_arginfo.h"
- # ifndef PHP_WIN32
- # include <sys/ipc.h>
- # include <sys/shm.h>
- #else
- #include "tsrm_win32.h"
- #endif
- #ifdef HAVE_SHMOP
- #include "ext/standard/info.h"
- /* {{{ shmop_module_entry */
- zend_module_entry shmop_module_entry = {
- STANDARD_MODULE_HEADER,
- "shmop",
- ext_functions,
- PHP_MINIT(shmop),
- NULL,
- NULL,
- NULL,
- PHP_MINFO(shmop),
- PHP_SHMOP_VERSION,
- STANDARD_MODULE_PROPERTIES
- };
- /* }}} */
- #ifdef COMPILE_DL_SHMOP
- ZEND_GET_MODULE(shmop)
- #endif
- typedef struct php_shmop
- {
- int shmid;
- key_t key;
- int shmflg;
- int shmatflg;
- char *addr;
- zend_long size;
- zend_object std;
- } php_shmop;
- zend_class_entry *shmop_ce;
- static zend_object_handlers shmop_object_handlers;
- static inline php_shmop *shmop_from_obj(zend_object *obj)
- {
- return (php_shmop *)((char *)(obj) - XtOffsetOf(php_shmop, std));
- }
- #define Z_SHMOP_P(zv) shmop_from_obj(Z_OBJ_P(zv))
- static zend_object *shmop_create_object(zend_class_entry *class_type)
- {
- php_shmop *intern = zend_object_alloc(sizeof(php_shmop), class_type);
- zend_object_std_init(&intern->std, class_type);
- object_properties_init(&intern->std, class_type);
- intern->std.handlers = &shmop_object_handlers;
- return &intern->std;
- }
- static zend_function *shmop_get_constructor(zend_object *object)
- {
- zend_throw_error(NULL, "Cannot directly construct Shmop, use shmop_open() instead");
- return NULL;
- }
- static void shmop_free_obj(zend_object *object)
- {
- php_shmop *shmop = shmop_from_obj(object);
- shmdt(shmop->addr);
- zend_object_std_dtor(&shmop->std);
- }
- /* {{{ PHP_MINIT_FUNCTION */
- PHP_MINIT_FUNCTION(shmop)
- {
- shmop_ce = register_class_Shmop();
- shmop_ce->create_object = shmop_create_object;
- memcpy(&shmop_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
- shmop_object_handlers.offset = XtOffsetOf(php_shmop, std);
- shmop_object_handlers.free_obj = shmop_free_obj;
- shmop_object_handlers.get_constructor = shmop_get_constructor;
- shmop_object_handlers.clone_obj = NULL;
- shmop_object_handlers.compare = zend_objects_not_comparable;
- return SUCCESS;
- }
- /* }}} */
- /* {{{ PHP_MINFO_FUNCTION */
- PHP_MINFO_FUNCTION(shmop)
- {
- php_info_print_table_start();
- php_info_print_table_row(2, "shmop support", "enabled");
- php_info_print_table_end();
- }
- /* }}} */
- /* {{{ gets and attaches a shared memory segment */
- PHP_FUNCTION(shmop_open)
- {
- zend_long key, mode, size;
- php_shmop *shmop;
- struct shmid_ds shm;
- char *flags;
- size_t flags_len;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "lsll", &key, &flags, &flags_len, &mode, &size) == FAILURE) {
- RETURN_THROWS();
- }
- if (flags_len != 1) {
- zend_argument_value_error(2, "must be a valid access mode");
- RETURN_THROWS();
- }
- object_init_ex(return_value, shmop_ce);
- shmop = Z_SHMOP_P(return_value);
- shmop->key = key;
- shmop->shmflg |= mode;
- switch (flags[0])
- {
- case 'a':
- shmop->shmatflg |= SHM_RDONLY;
- break;
- case 'c':
- shmop->shmflg |= IPC_CREAT;
- shmop->size = size;
- break;
- case 'n':
- shmop->shmflg |= (IPC_CREAT | IPC_EXCL);
- shmop->size = size;
- break;
- case 'w':
- /* noop
- shm segment is being opened for read & write
- will fail if segment does not exist
- */
- break;
- default:
- zend_argument_value_error(2, "must be a valid access mode");
- goto err;
- }
- if (shmop->shmflg & IPC_CREAT && shmop->size < 1) {
- zend_argument_value_error(4, "must be greater than 0 for the \"c\" and \"n\" access modes");
- goto err;
- }
- shmop->shmid = shmget(shmop->key, shmop->size, shmop->shmflg);
- if (shmop->shmid == -1) {
- php_error_docref(NULL, E_WARNING, "Unable to attach or create shared memory segment \"%s\"", strerror(errno));
- goto err;
- }
- if (shmctl(shmop->shmid, IPC_STAT, &shm)) {
- /* please do not add coverage here: the segment would be leaked and impossible to delete via php */
- php_error_docref(NULL, E_WARNING, "Unable to get shared memory segment information \"%s\"", strerror(errno));
- goto err;
- }
- if (shm.shm_segsz > ZEND_LONG_MAX) {
- zend_argument_value_error(4, "is too large");
- goto err;
- }
- shmop->addr = shmat(shmop->shmid, 0, shmop->shmatflg);
- if (shmop->addr == (char*) -1) {
- php_error_docref(NULL, E_WARNING, "Unable to attach to shared memory segment \"%s\"", strerror(errno));
- goto err;
- }
- shmop->size = shm.shm_segsz;
- return;
- err:
- zend_object_release(Z_OBJ_P(return_value));
- RETURN_FALSE;
- }
- /* }}} */
- /* {{{ reads from a shm segment */
- PHP_FUNCTION(shmop_read)
- {
- zval *shmid;
- zend_long start, count;
- php_shmop *shmop;
- char *startaddr;
- int bytes;
- zend_string *return_string;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "Oll", &shmid, shmop_ce, &start, &count) == FAILURE) {
- RETURN_THROWS();
- }
- shmop = Z_SHMOP_P(shmid);
- if (start < 0 || start > shmop->size) {
- zend_argument_value_error(2, "must be between 0 and the segment size");
- RETURN_THROWS();
- }
- if (count < 0 || start > (ZEND_LONG_MAX - count) || start + count > shmop->size) {
- zend_argument_value_error(3, "is out of range");
- RETURN_THROWS();
- }
- startaddr = shmop->addr + start;
- bytes = count ? count : shmop->size - start;
- return_string = zend_string_init(startaddr, bytes, 0);
- RETURN_NEW_STR(return_string);
- }
- /* }}} */
- /* {{{ used to close a shared memory segment; now a NOP */
- PHP_FUNCTION(shmop_close)
- {
- zval *shmid;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &shmid, shmop_ce) == FAILURE) {
- RETURN_THROWS();
- }
- }
- /* }}} */
- /* {{{ returns the shm size */
- PHP_FUNCTION(shmop_size)
- {
- zval *shmid;
- php_shmop *shmop;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &shmid, shmop_ce) == FAILURE) {
- RETURN_THROWS();
- }
- shmop = Z_SHMOP_P(shmid);
- RETURN_LONG(shmop->size);
- }
- /* }}} */
- /* {{{ writes to a shared memory segment */
- PHP_FUNCTION(shmop_write)
- {
- php_shmop *shmop;
- zend_long writesize;
- zend_long offset;
- zend_string *data;
- zval *shmid;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "OSl", &shmid, shmop_ce, &data, &offset) == FAILURE) {
- RETURN_THROWS();
- }
- shmop = Z_SHMOP_P(shmid);
- if ((shmop->shmatflg & SHM_RDONLY) == SHM_RDONLY) {
- zend_throw_error(NULL, "Read-only segment cannot be written");
- RETURN_THROWS();
- }
- if (offset < 0 || offset > shmop->size) {
- zend_argument_value_error(3, "is out of range");
- RETURN_THROWS();
- }
- writesize = ((zend_long)ZSTR_LEN(data) < shmop->size - offset) ? (zend_long)ZSTR_LEN(data) : shmop->size - offset;
- memcpy(shmop->addr + offset, ZSTR_VAL(data), writesize);
- RETURN_LONG(writesize);
- }
- /* }}} */
- /* {{{ mark segment for deletion */
- PHP_FUNCTION(shmop_delete)
- {
- zval *shmid;
- php_shmop *shmop;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &shmid, shmop_ce) == FAILURE) {
- RETURN_THROWS();
- }
- shmop = Z_SHMOP_P(shmid);
- if (shmctl(shmop->shmid, IPC_RMID, NULL)) {
- php_error_docref(NULL, E_WARNING, "Can't mark segment for deletion (are you the owner?)");
- RETURN_FALSE;
- }
- RETURN_TRUE;
- }
- /* }}} */
- #endif /* HAVE_SHMOP */
|