php-src/ext/rpc/rpc.c
2003-02-11 13:46:30 +00:00

937 lines
25 KiB
C

/*
+----------------------------------------------------------------------+
| PHP Version 4 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2003 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 2.02 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available at through the world-wide-web at |
| http://www.php.net/license/2_02.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. |
+----------------------------------------------------------------------+
| Author: Harald Radi <h.radi@nme.at> |
+----------------------------------------------------------------------+
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
#include "php_rpc.h"
#include "rpc.h"
#include "hash.h"
#include "handler.h"
static void rpc_instance_dtor(void *);
static void rpc_class_dtor(void *);
static void rpc_string_dtor(void *);
static void rpc_objects_delete(void *, zend_object_handle TSRMLS_DC);
static void rpc_ini_cb(void *arg TSRMLS_DC);
static rpc_class_hash *rpc_class_hash_find(rpc_string *name);
/* object handler */
static zval* rpc_read(zval *, zval * TSRMLS_DC);
static void rpc_write(zval *, zval *, zval * TSRMLS_DC);
static zval** rpc_get_property(zval *, zval * TSRMLS_DC);
static zval* rpc_get(zval * TSRMLS_DC);
static void rpc_set(zval **, zval * TSRMLS_DC);
static int rpc_has_property(zval *, zval *, int TSRMLS_DC);
static void rpc_unset_property(zval *, zval * TSRMLS_DC);
static HashTable* rpc_get_properties(zval * TSRMLS_DC);
static union _zend_function* rpc_get_method(zval *, char *, int TSRMLS_DC);
static union _zend_function* rpc_get_constructor(zval * TSRMLS_DC);
static zend_class_entry* rpc_get_class_entry(zval * TSRMLS_DC);
static int rpc_get_class_name(zval *object, char **class_name, zend_uint *class_name_len, int parent TSRMLS_DC);
static int rpc_compare(zval *, zval * TSRMLS_DC);
/**/
/* pseudo handler */
static void rpc_internal_get(rpc_internal *, char *, zend_uint, zval *);
static void rpc_internal_set(rpc_internal *, char *, zend_uint, zval *);
/**/
extern zend_object_handlers rpc_proxy_handlers;
static zend_object_handlers rpc_handlers = {
ZEND_OBJECTS_STORE_HANDLERS,
rpc_read,
rpc_write,
rpc_get_property,
NULL,
rpc_get,
rpc_set,
rpc_has_property,
rpc_unset_property,
rpc_get_properties,
rpc_get_method,
NULL,
rpc_get_constructor,
rpc_get_class_entry,
rpc_get_class_name,
rpc_compare
};
/* {{{ rpc_functions[]
*/
function_entry rpc_functions[] = {
{NULL, NULL, NULL}
};
/* }}} */
/* {{{ rpc_module_entry
*/
zend_module_entry rpc_module_entry = {
STANDARD_MODULE_HEADER,
"rpc",
rpc_functions,
ZEND_MINIT(rpc),
ZEND_MSHUTDOWN(rpc),
NULL,
NULL,
ZEND_MINFO(rpc),
"0.1a",
STANDARD_MODULE_PROPERTIES
};
/* }}} */
zend_class_entry rpc_class_entry;
static zend_class_entry *rpc_entry;
static zend_function *rpc_ctor;
static HashTable handlers;
static TsHashTable pool;
static TsHashTable classes;
static zend_llist classes_list;
static zend_llist layers;
#ifdef COMPILE_DL_RPC
ZEND_GET_MODULE(rpc);
#endif
/* {{{ ZEND_MINIT_FUNCTION
*/
ZEND_MINIT_FUNCTION(rpc)
{
zend_internal_function *zif;
/* rpc base class entry */
INIT_CLASS_ENTRY(rpc_class_entry, "rpc", NULL);
rpc_entry = zend_register_internal_class(&rpc_class_entry TSRMLS_CC);
zend_hash_init(&handlers, 0, NULL, NULL, TRUE);
zend_ts_hash_init(&pool, sizeof(rpc_internal **), NULL, rpc_instance_dtor, TRUE);
zend_ts_hash_init(&classes, 0, NULL, NULL, TRUE);
zend_llist_init(&classes_list, sizeof(rpc_class_hash **), rpc_class_dtor, TRUE);
zend_llist_init(&layers, sizeof(char *), NULL, TRUE);
zif = (zend_internal_function *) emalloc(sizeof(zend_internal_function));
zif->type = ZEND_INTERNAL_FUNCTION;
zif->function_name = rpc_entry->name;
zif->scope = rpc_entry;
zif->arg_types = NULL;
zif->handler = ZEND_FN(rpc_load);
/* add new constructor to the method table */
zend_hash_add(&(rpc_entry->function_table), rpc_entry->name, rpc_entry->name_length + 1, zif, sizeof(zend_function), &rpc_ctor);
efree(zif);
return SUCCESS;
}
/* }}} */
/* {{{ ZEND_MSHUTDOWN_FUNCTION
*/
ZEND_MSHUTDOWN_FUNCTION(rpc)
{
/* destroy instances first */
zend_ts_hash_destroy(&pool);
zend_ts_hash_destroy(&classes);
zend_llist_destroy(&classes_list);
zend_llist_destroy(&layers);
zend_hash_destroy(&handlers);
return SUCCESS;
}
/* }}} */
/* {{{ ZEND_MINFO_FUNCTION
*/
ZEND_MINFO_FUNCTION(rpc)
{
php_info_print_table_start();
zend_llist_apply(&layers, rpc_ini_cb TSRMLS_CC);
php_info_print_table_end();
DISPLAY_INI_ENTRIES();
}
/* }}} */
ZEND_API rpc_register_layer(rpc_handler_entry *entry TSRMLS_DC)
{
zend_class_entry ce;
INIT_CLASS_ENTRY(ce, entry->name, entry->methods);
ce.create_object = rpc_objects_new;
/* load all available rpc handler into a hash */
zend_hash_add(&handlers, entry->name, strlen(entry->name) + 1, &(entry->handlers), sizeof(rpc_object_handlers *), NULL);
zend_llist_add_element(&layers, &(entry->name));
/* register classes */
*(entry->ce) = zend_register_internal_class_ex(&ce, rpc_entry, NULL TSRMLS_CC);
}
static void rpc_class_dtor(void *pDest)
{
rpc_class_hash **hash;
hash = (rpc_class_hash **) pDest;
if ((*hash)->singleton) {
RPC_HT(*hash)->rpc_dtor((*hash)->data);
}
zend_ts_hash_destroy(&((*hash)->methods));
zend_ts_hash_destroy(&((*hash)->properties));
free((*hash)->name.str);
pefree((*hash), TRUE);
}
static void rpc_string_dtor(void *pDest)
{
rpc_string **string;
string = (rpc_string **) pDest;
free((*string)->str);
pefree(*string, TRUE);
}
static void rpc_instance_dtor(void *pDest)
{
rpc_internal **intern;
intern = (rpc_internal **) pDest;
RPC_HT(*intern)->rpc_dtor((*intern)->data);
tsrm_mutex_free((*intern)->mx_handler);
if ((*intern)->free_function_table) {
zend_ts_hash_destroy(&((*intern)->function_table));
}
pefree(*intern, TRUE);
}
static void rpc_ini_cb(void *arg TSRMLS_DC)
{
char *name = *((char **) arg);
php_info_print_table_header(2, name, "loaded");
}
static zend_object_value rpc_create_proxy(TSRMLS_D)
{
zend_object_value *zov;
rpc_proxy *proxy_intern;
/* set up the object value struct */
zov = (zend_object_value*) pemalloc(sizeof(zend_object_value), TRUE);
zov->handlers = &rpc_proxy_handlers;
/* set up the internal representation of the proxy */
proxy_intern = (rpc_proxy *) pemalloc(sizeof(rpc_proxy), TRUE);
/* store the instance in a hash and set the key as handle, thus
* we can find it later easily
*/
/* tsrm_mutex_lock(proxy->mx_writer);
{
zov->handle = zend_hash_next_free_element(TS_HASH(proxy));
zend_ts_hash_next_index_insert(proxy, &proxy_intern, sizeof(rpc_proxy *), NULL);
}
tsrm_mutex_unlock(proxy->mx_writer);
*/
return *zov;
}
/* object handler */
static void rpc_objects_delete(void *object, zend_object_handle handle TSRMLS_DC)
{
rpc_internal *intern = (rpc_internal *) object;
if (RPC_CLASS(intern) && RPC_CLASS(intern)->singleton) {
pefree(intern, TRUE);
} else if (RPC_CLASS(intern) && RPC_CLASS(intern)->poolable) {
if (RPC_CLASS(intern)->name.str) {
zend_ts_hash_add(&pool, RPC_CLASS(intern)->name.str, RPC_CLASS(intern)->name.len + 1, &intern, sizeof(rpc_internal *), NULL);
} else {
zend_ts_hash_index_update(&pool, RPC_CLASS(intern)->name.len + 1, &intern, sizeof(rpc_internal *), NULL);
}
} else {
if (intern->data != NULL) {
RPC_HT(intern)->rpc_dtor(intern->data);
}
pefree(intern, TRUE);
}
}
static zval* rpc_read(zval *object, zval *member TSRMLS_DC)
{
zval *return_value;
GET_INTERNAL(intern);
/* seting up the return value and decrease the refcounter as we don't
* keep a reference to this zval.
*/
MAKE_STD_ZVAL(return_value);
ZVAL_DELREF(return_value);
ZVAL_NULL(return_value);
if (intern->hash && Z_TYPE_P(member) == IS_LONG) {
rpc_internal_get(intern, NULL, Z_LVAL_P(member), return_value);
} else if (Z_TYPE_P(member) == IS_STRING) {
rpc_internal_get(intern, Z_STRVAL_P(member), Z_STRLEN_P(member), return_value);
} else {
/* TODO: exception here */
}
return return_value;
}
static void rpc_write(zval *object, zval *member, zval *value TSRMLS_DC)
{
GET_INTERNAL(intern);
if (intern->hash && Z_TYPE_P(member) == IS_LONG) {
rpc_internal_set(intern, NULL, Z_LVAL_P(member), value);
} else if (Z_TYPE_P(member) == IS_STRING) {
rpc_internal_set(intern, Z_STRVAL_P(member), Z_STRLEN_P(member), value);
} else {
/* TODO: exception here */
}
}
static zval** rpc_get_property(zval *object, zval *member TSRMLS_DC)
{
zval **return_value;
GET_INTERNAL(intern);
return_value = emalloc(sizeof(zval *));
MAKE_STD_ZVAL(*return_value);
Z_TYPE_P(object) = IS_OBJECT;
(*return_value)->value.obj = rpc_create_proxy(TSRMLS_C);
return return_value;
}
static zval* rpc_get(zval *property TSRMLS_DC)
{
/* not yet implemented */
return NULL;
}
static void rpc_set(zval **property, zval *value TSRMLS_DC)
{
/* not yet implemented */
}
static int rpc_has_property(zval *object, zval *member, int check_empty TSRMLS_DC)
{
// GET_INTERNAL(intern);
/* FIXME */
return FAILURE;
}
static void rpc_unset_property(zval *object, zval *member TSRMLS_DC)
{
// GET_INTERNAL(intern);
/* FIXME */
}
static HashTable* rpc_get_properties(zval *object TSRMLS_DC)
{
// GET_INTERNAL(intern);
/* FIXME */
return NULL;
}
static union _zend_function* rpc_get_method(zval *object, char *method, int method_len TSRMLS_DC)
{
zend_function *function;
unsigned char *ref_types = NULL;
GET_INTERNAL(intern);
if (zend_ts_hash_find(&intern->function_table, method, method_len + 1, &function) != SUCCESS) {
zend_internal_function *zif;
/* get reftypes */
if (RPC_HT(intern)->rpc_describe) {
char *arg_types;
rpc_string method_name;
method_name.str = method;
method_name.len = method_len;
RPC_HT(intern)->rpc_describe(method_name, intern->data, &arg_types, &ref_types);
}
zif = (zend_internal_function *) emalloc(sizeof(zend_internal_function));
zif->arg_types = ref_types;
zif->function_name = method;
zif->handler = ZEND_FN(rpc_call);
zif->scope = intern->ce;
zif->type = ZEND_INTERNAL_FUNCTION;
zif->fn_flags = ZEND_ACC_PUBLIC;
/* add new method to the method table */
zend_ts_hash_add(&intern->function_table, method, method_len + 1, zif, sizeof(zend_function), &function);
efree(zif);
}
return function;
}
static union _zend_function* rpc_get_constructor(zval *object TSRMLS_DC)
{
return rpc_ctor;
}
static zend_class_entry* rpc_get_class_entry(zval *object TSRMLS_DC)
{
GET_INTERNAL(intern);
return intern->ce;
}
static int rpc_get_class_name(zval *object, char **class_name, zend_uint *class_name_len, int parent TSRMLS_DC)
{
GET_INTERNAL(intern);
if (parent) {
return FAILURE;
} else {
*class_name = intern->ce->name;
*class_name_len = intern->ce->name_length;
return SUCCESS;
}
}
static int rpc_compare(zval *object1, zval *object2 TSRMLS_DC)
{
/* FIXME */
return FAILURE;
}
/**/
/* constructor */
ZEND_API ZEND_FUNCTION(rpc_load)
{
zval *object = getThis();
zval ***args, ***args_free;
zend_uint num_args = ZEND_NUM_ARGS();
rpc_class_hash *class_hash;
rpc_internal *intern;
rpc_string hash_val, class_val;
int retval, append = 0;
char *arg_types;
/* check if we were called as a constructor or as a function */
if (!object) {
/* we were called as a function so we have to figure out which rpc layer was requested
* and then we have to set up a zval containing the object
*/
/* get class entry */
GET_CLASS(ce);
/* set up a new zval container */
object = return_value;
Z_TYPE_P(object) = IS_OBJECT;
/* create a new object */
object->value.obj = rpc_objects_new(*ce TSRMLS_CC);
/* now everything is set up the same way as if we were called as a constructor */
}
if (GET_INTERNAL_EX(intern, object) != SUCCESS) {
/* TODO: exception */
}
/* fetch further parameters */
GET_ARGS_EX(num_args, args, args_free, 1);
/* if classname != integer */
if ((zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, 1 TSRMLS_CC, "l", &class_val.len) != SUCCESS) ||
/* or we have no hash function */
!(RPC_HT(intern)->rpc_hash) ||
/* or integer hashing is not allowed */
!(RPC_HT(intern)->hash_type & HASH_AS_INT)) {
/* else check for string - classname */
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, 1 TSRMLS_CC, "s", &class_val.str, &class_val.len) != SUCCESS) {
/* none of the two possibilities */
/* TODO: exception */
rpc_error(E_WARNING, "wrong arguments for %s()", get_active_function_name(TSRMLS_C));
ZVAL_NULL(object);
return;
} else {
/* hash classname if hashing function exists */
if (RPC_HT(intern)->rpc_hash) {
GET_SIGNATURE(intern, class_val.str, class_val.len, hash_val, num_args, arg_types);
/* check if already hashed */
if ((class_hash = rpc_class_hash_find(&hash_val)) == NULL) {
ALLOC_CLASS_HASH(class_hash, intern->handlers);
/* do hashing */
if (RPC_HT(intern)->rpc_hash(class_val, (rpc_string *) class_hash, NULL, num_args, arg_types, CLASS) != SUCCESS) {
/* TODO: exception */
ZVAL_NULL(object);
return;
}
/* overload class entry */
RPC_HT(intern)->rpc_name(class_val, &class_val, NULL, CLASS);
OVERLOAD_RPC_CLASS(class_val, intern, class_hash);
/* register with non-hashed key
* also track all instaces in a llist for destruction later on, because there might be duplicate entries in
* the hashtable and we can't determine if a pointer references to an already freed element
*/
REGISTER_RPC_CLASS(class_val, class_hash);
} else {
INIT_RPC_OBJECT(intern, class_hash);
}
FREE_SIGNATURE(hash_val, arg_types);
} else {
/* Copy the function table hash for this object, so that it is separated
* from the "global" table */
SEPARATE_RPC_CLASS(intern);
}
}
} else {
/* integer classname (hashcode) */
if ((class_hash = rpc_class_hash_find(&hash_val)) == NULL) {
ALLOC_CLASS_HASH(class_hash, intern->handlers);
class_val.str = NULL;
class_hash->name.str = NULL;
class_hash->name.len = class_val.len;
/* overload class entry */
RPC_HT(intern)->rpc_name(class_val, &class_val, NULL, CLASS);
OVERLOAD_RPC_CLASS(class_val, intern, class_hash);
/* register int hashcode, we don't know more */
REGISTER_RPC_CLASS(class_val, class_hash);
} else {
INIT_RPC_OBJECT(intern, class_hash);
}
}
/* if hash function available */
if (RPC_HT(intern)->rpc_hash) {
rpc_internal *pool_intern;
/* assign cache structure */
RPC_CLASS(intern) = class_hash;
if (zend_ts_hash_remove_key_or_index(&pool, RPC_CLASS(intern)->name.str, RPC_CLASS(intern)->name.len + 1, (void **) &pool_intern) == SUCCESS) {
intern->data = pool_intern->data;
pefree(pool_intern, TRUE);
retval = SUCCESS;
} else if (RPC_CLASS(intern)->singleton) {
/* singleton */
intern->data = RPC_CLASS(intern)->data;
retval = SUCCESS;
} else {
/* call the rpc ctor */
retval = RPC_HT(intern)->rpc_ctor(class_hash->name, &(intern->data), num_args, args);
}
} else {
/* disable caching from now on */
intern->hash = NULL;
/* call the rpc ctor */
retval = RPC_HT(intern)->rpc_ctor(class_val, &(intern->data), num_args, args);
}
efree(args_free);
if (retval != SUCCESS) {
/* TODO: exception */
RETURN_NULL();
}
}
ZEND_API ZEND_FUNCTION(rpc_call)
{
zval *object = getThis();
zval ***args, ***args_free;
zend_uint num_args = ZEND_NUM_ARGS();
char *hash = NULL, *arg_types;
int hash_len, retval, strip = 0;
/* check if we were called as a method or as a function */
if (!object) {
/* we were called as a function so we have to figure out which rpc layer was requested */
/* get class entry */
GET_CLASS(ce);
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, 2 TSRMLS_CC, "Ol", &object, *ce, &hash_len) != SUCCESS) {
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, 2 TSRMLS_CC, "Os", &object, *ce, &hash, &hash_len) != SUCCESS) {
/* none of the two possibilities */
/* TODO: exception */
rpc_error(E_WARNING, "wrong arguments for %s()", get_active_function_name(TSRMLS_C));
}
}
strip = 2;
} else {
hash = get_active_function_name(TSRMLS_C);
hash_len = strlen(hash);
}
GET_ARGS_EX(num_args, args, args_free, strip);
/* scope for internal data */
{
rpc_string hash_val, *method_hash, **method_hash_find;
GET_INTERNAL(intern);
method_hash = (rpc_string *) pemalloc(sizeof(rpc_string), TRUE);
method_hash->str = hash;
method_hash->len = hash_len;
if (intern->hash) {
/* cache method table lookups */
if (!hash && !(RPC_HT(intern)->hash_type & HASH_AS_INT)) {
/* TODO: exception */
} else if(hash) {
/* string passed */
GET_METHOD_SIGNATURE(intern, method_hash, hash_val, num_args, arg_types);
/* check if already hashed */
if (zend_ts_hash_find(&(intern->hash->methods), hash_val.str, hash_val.len + 1, (void **) &method_hash_find) != SUCCESS) {
if (RPC_HT(intern)->rpc_hash(*method_hash, method_hash, intern->data, num_args, arg_types, METHOD) != SUCCESS) {
/* TODO: exception */
RETURN_NULL();
}
/* register with non-hashed key */
zend_ts_hash_add(&(intern->hash->methods), hash_val.str, hash_val.len + 1, &method_hash, sizeof(rpc_string *), NULL);
} else {
pefree(method_hash, TRUE);
method_hash = *method_hash_find;
}
FREE_SIGNATURE(hash_val, arg_types);
}
}
/* actually this should not be neccesary, but who knows :)
* considering possible thread implementations in future php versions
* and srm it is better to do concurrency checks
* DEPRECATE THIS !
*/
tsrm_mutex_lock(intern->mx_handler);
retval = RPC_HT(intern)->rpc_call(*method_hash, intern->data, return_value, num_args, args);
tsrm_mutex_unlock(intern->mx_handler);
}
efree(args_free);
if (retval != SUCCESS) {
/* TODO: exception here */
}
}
ZEND_API ZEND_FUNCTION(rpc_set)
{
zval *object, *value;
char *property = NULL;
int property_len;
rpc_internal *intern;
/* get class entry */
GET_CLASS(ce);
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, 3 TSRMLS_CC, "Olz", &object, *ce, &property_len, &value) != SUCCESS) {
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, 3 TSRMLS_CC, "Osz", &object, *ce, &property, &property_len, &value) != SUCCESS) {
/* none of the two possibilities */
/* TODO: exception */
rpc_error(E_WARNING, "wrong arguments for %s()", get_active_function_name(TSRMLS_C));
}
}
GET_INTERNAL_EX(intern, object);
if (!property && !intern->hash) {
/* TODO: exception here */
} else {
rpc_internal_set(intern, property, property_len, value);
}
}
ZEND_API ZEND_FUNCTION(rpc_get)
{
zval *object;
char *property = NULL;
int property_len;
rpc_internal *intern;
/* get class entry */
GET_CLASS(ce);
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, 2 TSRMLS_CC, "Ol", &object, *ce, &property_len) != SUCCESS) {
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, 2 TSRMLS_CC, "Os", &object, *ce, &property, &property_len) != SUCCESS) {
/* none of the two possibilities */
/* TODO: exception */
rpc_error(E_WARNING, "wrong arguments for %s()", get_active_function_name(TSRMLS_C));
}
}
GET_INTERNAL_EX(intern, object);
if (!property && !intern->hash) {
/* TODO: exception here */
} else {
rpc_internal_get(intern, property, property_len, return_value);
}
}
ZEND_API ZEND_FUNCTION(rpc_singleton)
{
zval *object;
rpc_internal *intern;
/* get class entry */
GET_CLASS(ce);
zend_parse_parameters(1 TSRMLS_CC, "O", &object, *ce);
GET_INTERNAL_EX(intern, object);
if (!RPC_CLASS(intern)) {
/* TODO: exception here, no hashing */
} else if (!RPC_CLASS(intern)->singleton) {
RPC_CLASS(intern)->singleton = TRUE;
RPC_CLASS(intern)->data = intern->data;
}
}
ZEND_API ZEND_FUNCTION(rpc_poolable)
{
zval *object;
rpc_internal *intern;
/* get class entry */
GET_CLASS(ce);
zend_parse_parameters(1 TSRMLS_CC, "O", &object, *ce);
GET_INTERNAL_EX(intern, object);
if (RPC_HT(intern)->poolable && RPC_CLASS(intern) && (RPC_HT(intern)->poolable == TRUE)) {
RPC_CLASS(intern)->poolable = TRUE;
} else {
/* TODO: exception here, no hashing */
}
}
ZEND_API void rpc_error(int type, const char *format, ...)
{
va_list args;
TSRMLS_FETCH();
va_start(args, format);
zend_error_cb(type, zend_get_executed_filename(TSRMLS_C), zend_get_executed_lineno(TSRMLS_C), format, args);
va_end(args);
}
ZEND_API zend_object_value rpc_objects_new(zend_class_entry *class_type TSRMLS_DC)
{
zend_object_value zov;
rpc_internal *intern;
/* set up the object value struct */
zov.handlers = &rpc_handlers;
/* set up the internal representation of our rpc instance */
intern = (rpc_internal *) pecalloc(1, sizeof(rpc_internal), TRUE);
intern->ce = class_type;
intern->data = NULL;
intern->free_function_table = 0;
intern->function_table.reader = 0;
intern->function_table.mx_reader = tsrm_mutex_alloc();
intern->function_table.mx_writer = tsrm_mutex_alloc();
intern->mx_handler = tsrm_mutex_alloc();
if (zend_hash_find(&handlers, class_type->name, class_type->name_length + 1, (void **) &(intern->handlers)) != SUCCESS) {
/* TODO: exception */
}
zov.handle = zend_objects_store_put(intern, rpc_objects_delete, NULL TSRMLS_CC);
return zov;
}
/*******************/
static void rpc_internal_get(rpc_internal *intern, char *property, zend_uint property_len, zval *return_value)
{
int retval;
rpc_string *property_hash, **property_hash_find;
Z_TYPE_P(return_value) = IS_NULL;
property_hash = (rpc_string *) pemalloc(sizeof(rpc_string), TRUE);
property_hash->str = property;
property_hash->len = property_len;
if (intern->hash) {
/* cache method table lookups */
if (!property && !(RPC_HT(intern)->hash_type & HASH_AS_INT)) {
/* TODO: exception */
} else if(property) {
/* check if already hashed */
if (zend_ts_hash_find(&(intern->hash->properties), property, property_len + 1, (void **) &property_hash_find) != SUCCESS) {
if (RPC_HT(intern)->rpc_hash(*property_hash, property_hash, intern->data, 0, NULL, PROPERTY) != SUCCESS) {
/* TODO: exception */
RETURN_NULL();
}
/* register with non-hashed key */
zend_ts_hash_add(&(intern->hash->properties), property, property_len + 1, &property_hash, sizeof(rpc_string *), NULL);
} else {
pefree(property_hash, TRUE);
property_hash = *property_hash_find;
}
}
}
tsrm_mutex_lock(intern->mx_handler);
retval = RPC_HT(intern)->rpc_get(*property_hash, return_value, intern->data);
tsrm_mutex_unlock(intern->mx_handler);
if (retval != SUCCESS) {
/* TODO: exception here */
}
}
static void rpc_internal_set(rpc_internal *intern, char *property, zend_uint property_len, zval *value)
{
int retval;
rpc_string property_name;
property_name.str = property;
property_name.len = property_len;
tsrm_mutex_lock(intern->mx_handler);
retval = RPC_HT(intern)->rpc_set(property_name, value, intern->data);
tsrm_mutex_unlock(intern->mx_handler);
if (retval != SUCCESS) {
/* TODO: exception here */
}
}
static rpc_class_hash *rpc_class_hash_find(rpc_string *name)
{
rpc_class_hash **class_hash_find = NULL;
if (name->str == NULL) {
/* int value */
if (zend_ts_hash_index_find(&classes, name->len, (void**) &class_hash_find) != SUCCESS) {
return NULL;
}
} else {
/* string value */
if (zend_ts_hash_find(&classes, name->str, name->len + 1, (void **) &class_hash_find) != SUCCESS) {
return NULL;
}
}
return *class_hash_find;
}
ZEND_API zval* _rpc_object_from_data(zval *z, rpc_handler_entry *handler, void *data, rpc_class_hash *class_hash)
{
rpc_internal *intern;
rpc_string hash, name = {NULL, 0};
TSRMLS_FETCH();
if (z == NULL) {
ALLOC_ZVAL(z);
}
Z_TYPE_P(z) = IS_OBJECT;
z->value.obj = rpc_objects_new(*(handler->ce) TSRMLS_CC);
if (GET_INTERNAL_EX(intern, z) != SUCCESS) {
/* TODO: exception */
return NULL;
}
intern->ce = *(handler->ce);
intern->data = data;
if ((handler->handlers->rpc_hash) &&
(handler->handlers->rpc_hash(name, &hash, data, 0, "", CLASS) == SUCCESS)) {
/* We are hashing, try to find an appropriate hash or create a new one */
if ((class_hash == NULL) &&
((class_hash = rpc_class_hash_find(&hash)) == NULL)) {
ALLOC_CLASS_HASH(class_hash, intern->handlers);
class_hash->name = hash;
if (handler->handlers->rpc_name(hash, &name, data, CLASS) != SUCCESS) {
/* TODO exception */
}
OVERLOAD_RPC_CLASS(name, intern, class_hash);
REGISTER_RPC_CLASS(name, class_hash);
} else {
INIT_RPC_OBJECT(intern, class_hash);
}
RPC_CLASS(intern) = class_hash;
} else {
/* Copy the function table hash for this object, so that it is separated
* from the "global" table */
SEPARATE_RPC_CLASS(intern);
}
return z;
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/