aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/php/ext/grpc/call.c
diff options
context:
space:
mode:
authorGravatar mlumish <mlumish@google.com>2014-12-09 16:28:23 -0800
committerGravatar Michael Lumish <mlumish@google.com>2014-12-09 17:50:41 -0800
commitb892a27e67e534eccf011ab8c68d455c5be77e6c (patch)
tree7d1475a645c6ac60ff0ee28f26425734048480cb /src/php/ext/grpc/call.c
parent275b3ac04dbe5654a38de47e7f4ee6b9b7ca7b8e (diff)
Added PHP to the global gRPC moe config
Change on 2014/12/09 by mlumish <mlumish@google.com> ------------- Created by MOE: http://code.google.com/p/moe-java MOE_MIGRATED_REVID=81727766
Diffstat (limited to 'src/php/ext/grpc/call.c')
-rwxr-xr-xsrc/php/ext/grpc/call.c454
1 files changed, 454 insertions, 0 deletions
diff --git a/src/php/ext/grpc/call.c b/src/php/ext/grpc/call.c
new file mode 100755
index 0000000000..be7969f927
--- /dev/null
+++ b/src/php/ext/grpc/call.c
@@ -0,0 +1,454 @@
+#include "call.h"
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "php.h"
+#include "php_ini.h"
+#include "ext/standard/info.h"
+#include "ext/spl/spl_exceptions.h"
+#include "php_grpc.h"
+
+#include "zend_exceptions.h"
+#include "zend_hash.h"
+
+#include <stdbool.h>
+
+#include "grpc/support/log.h"
+#include "grpc/grpc.h"
+
+#include "timeval.h"
+#include "channel.h"
+#include "completion_queue.h"
+#include "byte_buffer.h"
+
+/* Frees and destroys an instance of wrapped_grpc_call */
+void free_wrapped_grpc_call(void *object TSRMLS_DC){
+ wrapped_grpc_call *call = (wrapped_grpc_call*)object;
+ if(call->wrapped != NULL){
+ grpc_call_destroy(call->wrapped);
+ }
+ efree(call);
+}
+
+/* Initializes an instance of wrapped_grpc_call to be associated with an object
+ * of a class specified by class_type */
+zend_object_value create_wrapped_grpc_call(
+ zend_class_entry *class_type TSRMLS_DC){
+ zend_object_value retval;
+ wrapped_grpc_call *intern;
+
+ intern = (wrapped_grpc_call*)emalloc(sizeof(wrapped_grpc_call));
+ memset(intern, 0, sizeof(wrapped_grpc_call));
+
+ zend_object_std_init(&intern->std, class_type TSRMLS_CC);
+ object_properties_init(&intern->std, class_type);
+ retval.handle = zend_objects_store_put(
+ intern,
+ (zend_objects_store_dtor_t) zend_objects_destroy_object,
+ free_wrapped_grpc_call,
+ NULL TSRMLS_CC);
+ retval.handlers = zend_get_std_object_handlers();
+ return retval;
+}
+
+zval *grpc_php_wrap_call(grpc_call *wrapped){
+ zval *call_object;
+ MAKE_STD_ZVAL(call_object);
+ object_init_ex(call_object, grpc_ce_call);
+ wrapped_grpc_call *call = (wrapped_grpc_call*)zend_object_store_get_object(
+ call_object TSRMLS_CC);
+ call->wrapped = wrapped;
+ return call_object;
+}
+
+zval *grpc_call_create_metadata_array(int count, grpc_metadata *elements){
+ int i;
+ zval *array;
+ zval **data = NULL;
+ HashTable *array_hash;
+ zval *inner_array;
+ char *str_key;
+ char *str_val;
+ size_t key_len;
+ MAKE_STD_ZVAL(array);
+ array_init(array);
+ array_hash = Z_ARRVAL_P(array);
+ grpc_metadata *elem;
+ for(i=0; i<count; i++){
+ elem = &elements[i];
+ key_len = strlen(elem->key);
+ str_key = ecalloc(key_len+1, sizeof(char));
+ memcpy(str_key, elem->key, key_len);
+ str_val = ecalloc(elem->value_length+1, sizeof(char));
+ memcpy(str_val, elem->value, elem->value_length);
+ if(zend_hash_find(array_hash,
+ str_key,
+ key_len,
+ (void**)data) == SUCCESS){
+ switch(Z_TYPE_P(*data)){
+ case IS_STRING:
+ MAKE_STD_ZVAL(inner_array);
+ array_init(inner_array);
+ add_next_index_zval(inner_array, *data);
+ add_assoc_zval(array, str_key, inner_array);
+ break;
+ case IS_ARRAY:
+ inner_array = *data;
+ break;
+ default:
+ zend_throw_exception(zend_exception_get_default(),
+ "Metadata hash somehow contains wrong types.",
+ 1 TSRMLS_CC);
+ efree(str_key);
+ efree(str_val);
+ return NULL;
+ }
+ add_next_index_stringl(inner_array,
+ str_val,
+ elem->value_length,
+ false);
+ } else {
+ add_assoc_stringl(array,
+ str_key,
+ str_val,
+ elem->value_length,
+ false);
+ }
+ }
+ return array;
+}
+
+int php_grpc_call_add_metadata_array_walk(void *elem TSRMLS_DC,
+ int num_args,
+ va_list args,
+ zend_hash_key *hash_key){
+ zval **data = (zval**)elem;
+ grpc_metadata metadata;
+ grpc_call *call = va_arg(args, grpc_call*);
+ gpr_uint32 flags = va_arg(args, gpr_uint32);
+ const char *key;
+ HashTable *inner_hash;
+ /* We assume that either two args were passed, and we are in the recursive
+ case (and the second argument is the key), or one arg was passed and
+ hash_key is the string key. */
+ if(num_args > 2){
+ key = va_arg(args, const char*);
+ } else {
+ /* TODO(mlumish): If possible, check that hash_key is a string */
+ key = hash_key->arKey;
+ }
+ switch(Z_TYPE_P(*data)){
+ case IS_STRING:
+ metadata.key = (char*)key;
+ metadata.value = Z_STRVAL_P(*data);
+ metadata.value_length = Z_STRLEN_P(*data);
+ grpc_call_add_metadata(call, &metadata, 0u);
+ break;
+ case IS_ARRAY:
+ inner_hash = Z_ARRVAL_P(*data);
+ zend_hash_apply_with_arguments(inner_hash TSRMLS_CC,
+ php_grpc_call_add_metadata_array_walk,
+ 3,
+ call,
+ flags,
+ key);
+ break;
+ default:
+ zend_throw_exception(zend_exception_get_default(),
+ "Metadata hash somehow contains wrong types.",
+ 1 TSRMLS_CC);
+ }
+ return ZEND_HASH_APPLY_KEEP;
+}
+
+/**
+ * Constructs a new instance of the Call class.
+ * @param Channel $channel The channel to associate the call with. Must not be
+ * closed.
+ * @param string $method The method to call
+ * @param Timeval $absolute_deadline The deadline for completing the call
+ */
+PHP_METHOD(Call, __construct){
+ wrapped_grpc_call *call = (wrapped_grpc_call*)zend_object_store_get_object(
+ getThis() TSRMLS_CC);
+ zval *channel_obj;
+ char *method;
+ int method_len;
+ zval *deadline_obj;
+ /* "OsO" == 1 Object, 1 string, 1 Object */
+ if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
+ "OsO",
+ &channel_obj, grpc_ce_channel,
+ &method, &method_len,
+ &deadline_obj, grpc_ce_timeval) == FAILURE){
+ zend_throw_exception(spl_ce_InvalidArgumentException,
+ "Call expects a Channel, a String, and a Timeval",
+ 1 TSRMLS_CC);
+ return;
+ }
+ wrapped_grpc_channel *channel =
+ (wrapped_grpc_channel*)zend_object_store_get_object(channel_obj TSRMLS_CC);
+ if(channel->wrapped == NULL) {
+ zend_throw_exception(spl_ce_InvalidArgumentException,
+ "Call cannot be constructed from a closed Channel",
+ 1 TSRMLS_CC);
+ return;
+ }
+ add_property_zval(getThis(), "channel", channel_obj);
+ wrapped_grpc_timeval *deadline =
+ (wrapped_grpc_timeval*)zend_object_store_get_object(deadline_obj TSRMLS_CC);
+ call->wrapped = grpc_channel_create_call(channel->wrapped,
+ method,
+ channel->target,
+ deadline->wrapped);
+}
+
+/**
+ * Add metadata to the call. All array keys must be strings. If the value is a
+ * string, it is added as a key/value pair. If it is an array, each value is
+ * added paired with the same string
+ * @param array $metadata The metadata to add
+ * @param long $flags A bitwise combination of the Grpc\WRITE_* constants
+ * (optional)
+ * @return Void
+ */
+PHP_METHOD(Call, add_metadata){
+ wrapped_grpc_call *call = (wrapped_grpc_call*)zend_object_store_get_object(
+ getThis() TSRMLS_CC);
+ zval *array;
+ HashTable *array_hash;
+ long flags = 0;
+ /* "a|l" == 1 array, 1 optional long */
+ if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
+ "a|l",
+ &array,
+ &flags) == FAILURE){
+ zend_throw_exception(spl_ce_InvalidArgumentException,
+ "add_metadata expects an array and an optional long",
+ 1 TSRMLS_CC);
+ return;
+ }
+ array_hash = Z_ARRVAL_P(array);
+ zend_hash_apply_with_arguments(array_hash TSRMLS_CC,
+ php_grpc_call_add_metadata_array_walk,
+ 2,
+ call->wrapped,
+ (gpr_uint32)flags);
+}
+
+/**
+ * Invoke the RPC. Starts sending metadata and request headers over the wire
+ * @param CompletionQueue $queue The completion queue to use with this call
+ * @param long $invoke_accepted_tag The tag to associate with this invocation
+ * @param long $metadata_tag The tag to associate with returned metadata
+ * @param long $finished_tag The tag to associate with the finished event
+ * @param long $flags A bitwise combination of the Grpc\WRITE_* constants
+ * (optional)
+ * @return long Error code
+ */
+PHP_METHOD(Call, start_invoke){
+ long tag1;
+ long tag2;
+ long tag3;
+ zval *queue_obj;
+ long flags = 0;
+ /* "Olll|l" == 1 Object, 3 mandatory longs, 1 optional long */
+ if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
+ "Olll|l",
+ &queue_obj, grpc_ce_completion_queue,
+ &tag1,
+ &tag2,
+ &tag3,
+ &flags) == FAILURE){
+ zend_throw_exception(
+ spl_ce_InvalidArgumentException,
+ "start_invoke needs a CompletionQueue, 3 longs, and an optional long",
+ 1 TSRMLS_CC);
+ return;
+ }
+ add_property_zval(getThis(), "completion_queue", queue_obj);
+ wrapped_grpc_call *call = (wrapped_grpc_call*)zend_object_store_get_object(
+ getThis() TSRMLS_CC);
+ wrapped_grpc_completion_queue *queue =
+ (wrapped_grpc_completion_queue*)zend_object_store_get_object(
+ queue_obj TSRMLS_CC);
+ RETURN_LONG(grpc_call_start_invoke(call->wrapped,
+ queue->wrapped,
+ (void*)tag1,
+ (void*)tag2,
+ (void*)tag3,
+ (gpr_uint32)flags));
+}
+
+/**
+ * Accept an incoming RPC, binding a completion queue to it. To be called after
+ * adding metadata to the call, but before sending messages. Can only be called
+ * on the server
+ * @param CompletionQueue $queue The completion queue to use with this call
+ * @param long $finished_tag The tag to associate with the finished event
+ * @param long $flags A bitwise combination of the Grpc\WRITE_* constants
+ * (optional)
+ * @return long Error code
+ */
+PHP_METHOD(Call, accept){
+ long tag;
+ zval *queue_obj;
+ long flags = 0;
+ /* "Ol|l" == 1 Object, 1 mandatory long, 1 optional long */
+ if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
+ "Ol|l",
+ &queue_obj, grpc_ce_completion_queue,
+ &tag,
+ &flags) == FAILURE){
+ zend_throw_exception(
+ spl_ce_InvalidArgumentException,
+ "accept expects a CompletionQueue, a long, and an optional long",
+ 1 TSRMLS_CC);
+ return;
+ }
+ add_property_zval(getThis(), "completion_queue", queue_obj);
+ wrapped_grpc_call *call = (wrapped_grpc_call*)zend_object_store_get_object(
+ getThis() TSRMLS_CC);
+ wrapped_grpc_completion_queue *queue =
+ (wrapped_grpc_completion_queue*)zend_object_store_get_object(
+ queue_obj TSRMLS_CC);
+ RETURN_LONG(grpc_call_accept(call->wrapped,
+ queue->wrapped,
+ (void*)tag,
+ (gpr_uint32)flags));
+}
+
+/**
+ * Called by clients to cancel an RPC on the server.
+ * @return long Error code
+ */
+PHP_METHOD(Call, cancel){
+ wrapped_grpc_call *call = (wrapped_grpc_call*)zend_object_store_get_object(
+ getThis() TSRMLS_CC);
+ RETURN_LONG(grpc_call_cancel(call->wrapped));
+}
+
+/**
+ * Queue a byte buffer for writing
+ * @param string $buffer The buffer to queue for writing
+ * @param long $tag The tag to associate with this write
+ * @param long $flags A bitwise combination of the Grpc\WRITE_* constants
+ * (optional)
+ * @return long Error code
+ */
+PHP_METHOD(Call, start_write){
+ wrapped_grpc_call *call = (wrapped_grpc_call*)zend_object_store_get_object(
+ getThis() TSRMLS_CC);
+ char *buffer;
+ int buffer_len;
+ long tag;
+ long flags = 0;
+ /* "Ol|l" == 1 Object, 1 mandatory long, 1 optional long */
+ if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
+ "sl|l",
+ &buffer, &buffer_len,
+ &tag,
+ &flags) == FAILURE){
+ zend_throw_exception(
+ spl_ce_InvalidArgumentException,
+ "start_write expects a string and an optional long",
+ 1 TSRMLS_CC);
+ return;
+ }
+ RETURN_LONG(grpc_call_start_write(call->wrapped,
+ string_to_byte_buffer(buffer, buffer_len),
+ (void*)tag,
+ (gpr_uint32)flags));
+}
+
+/**
+ * Queue a status for writing
+ * @param long $status_code The status code to send
+ * @param string $status_details The status details to send
+ * @param long $tag The tag to associate with this status
+ * @return long Error code
+ */
+PHP_METHOD(Call, start_write_status){
+ wrapped_grpc_call *call = (wrapped_grpc_call*)zend_object_store_get_object(
+ getThis() TSRMLS_CC);
+ long status_code;
+ int status_details_length;
+ long tag;
+ grpc_status status;
+ /* "lsl" == 1 long, 1 string, 1 long */
+ if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
+ "lsl",
+ &status_code,
+ &status.details, &status_details_length,
+ &tag) == FAILURE){
+ zend_throw_exception(
+ spl_ce_InvalidArgumentException,
+ "start_write_status expects a long, a string, and a long",
+ 1 TSRMLS_CC);
+ return;
+ }
+ status.code = (gpr_uint32)status_code;
+ RETURN_LONG(grpc_call_start_write_status(call->wrapped,
+ status,
+ (void*)tag));
+}
+
+/**
+ * Indicate that there are no more messages to send
+ * @return long Error code
+ */
+PHP_METHOD(Call, writes_done){
+ wrapped_grpc_call *call = (wrapped_grpc_call*)zend_object_store_get_object(
+ getThis() TSRMLS_CC);
+ long tag;
+ /* "l" == 1 long */
+ if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &tag) == FAILURE){
+ zend_throw_exception(spl_ce_InvalidArgumentException,
+ "writes_done expects a long",
+ 1 TSRMLS_CC);
+ return;
+ }
+ RETURN_LONG(grpc_call_writes_done(call->wrapped, (void*)tag));
+}
+
+/**
+ * Initiate a read on a call. Output event contains a byte buffer with the
+ * result of the read
+ * @param long $tag The tag to associate with this read
+ * @return long Error code
+ */
+PHP_METHOD(Call, start_read){
+ wrapped_grpc_call *call = (wrapped_grpc_call*)zend_object_store_get_object(
+ getThis() TSRMLS_CC);
+ long tag;
+ /* "l" == 1 long */
+ if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &tag) == FAILURE){
+ zend_throw_exception(spl_ce_InvalidArgumentException,
+ "start_read expects a long",
+ 1 TSRMLS_CC);
+ return;
+ }
+ RETURN_LONG(grpc_call_start_read(call->wrapped, (void*)tag));
+}
+
+static zend_function_entry call_methods[] = {
+ PHP_ME(Call, __construct, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
+ PHP_ME(Call, accept, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(Call, add_metadata, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(Call, cancel, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(Call, start_invoke, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(Call, start_read, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(Call, start_write, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(Call, start_write_status, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(Call, writes_done, NULL, ZEND_ACC_PUBLIC)
+ PHP_FE_END
+};
+
+void grpc_init_call(TSRMLS_D){
+ zend_class_entry ce;
+ INIT_CLASS_ENTRY(ce, "Grpc\\Call", call_methods);
+ ce.create_object = create_wrapped_grpc_call;
+ grpc_ce_call = zend_register_internal_class(&ce TSRMLS_CC);
+}