Updated C extension to new call API

pull/1014/head
murgatroid99 10 years ago
parent 79c7f85ba7
commit afd541cbd3
  1. 523
      src/php/ext/grpc/call.c
  2. 14
      src/php/ext/grpc/call.h
  3. 1
      src/php/ext/grpc/channel.c
  4. 168
      src/php/ext/grpc/completion_queue.c
  5. 62
      src/php/ext/grpc/completion_queue.h
  6. 2
      src/php/ext/grpc/config.m4
  7. 150
      src/php/ext/grpc/event.c
  8. 51
      src/php/ext/grpc/event.h
  9. 36
      src/php/ext/grpc/php_grpc.c
  10. 75
      src/php/ext/grpc/server.c
  11. 1
      src/php/ext/grpc/server.h

@ -49,16 +49,28 @@
#include <stdbool.h>
#include "grpc/support/log.h"
#include "grpc/support/alloc.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;
grpc_event *event;
if (call->queue != NULL) {
grpc_completion_queue_shutdown(call->queue);
event = grpc_completion_queue_next(call->queue, gpr_inf_future);
while (event != NULL) {
if (event->type == GRPC_QUEUE_SHUTDOWN) {
break;
}
event = grpc_completion_queue_next(call->queue, gpr_inf_future);
}
grpc_completion_queue_destroy(call->queue);
}
if (call->owned && call->wrapped != NULL) {
grpc_call_destroy(call->wrapped);
}
@ -93,10 +105,13 @@ zval *grpc_php_wrap_call(grpc_call *wrapped, bool owned) {
wrapped_grpc_call *call =
(wrapped_grpc_call *)zend_object_store_get_object(call_object TSRMLS_CC);
call->wrapped = wrapped;
call->queue = grpc_completion_queue_create();
return call_object;
}
zval *grpc_call_create_metadata_array(int count, grpc_metadata *elements) {
zval *grpc_parse_metadata_array(grpc_metadata_array *metadata_array) {
int count = metadata_array->count;
grpc_metadata *elements = metadata_array->metadata;
int i;
zval *array;
zval **data = NULL;
@ -137,6 +152,62 @@ zval *grpc_call_create_metadata_array(int count, grpc_metadata *elements) {
return array;
}
bool create_metadata_array(zval *array, grpc_metadata_array *metadata) {
zval **inner_array;
zval **value;
HashTable *array_hash;
HashPosition array_pointer;
HashTable *inner_array_hash;
HashPosition inner_array_pointer;
char *key;
uint key_len;
ulong index;
if (Z_TYPE_P(array) != IS_ARRAY) {
return false;
}
grpc_metadata_array_init(metadata);
array_hash = Z_ARRVAL_P(array);
for (zend_hash_internal_pointer_reset_ex(array_hash, &array_pointer);
zend_hash_get_current_data_ex(array_hash, (void**)&inner_array,
&array_pointer) == SUCCESS;
zend_hash_move_forward_ex(array_hash, &array_pointer)) {
if (zend_hash_get_current_key_ex(array_hash, &key, &key_len, &index, 0,
&array_pointer) != HASH_KEY_IS_STRING) {
return false;
}
if (Z_TYPE_P(*inner_array) != IS_ARRAY) {
return false;
}
inner_array_hash = Z_ARRVAL_P(*inner_array);
metadata->capacity += zend_hash_num_elements(inner_array_hash);
}
metadata->metadata = gpr_malloc(metadata->capacity * sizeof(grpc_metadata));
for (zend_hash_internal_pointer_reset_ex(array_hash, &array_pointer);
zend_hash_get_current_data_ex(array_hash, (void**)&inner_array,
&array_pointer) == SUCCESS;
zend_hash_move_forward_ex(array_hash, &array_pointer)) {
if (zend_hash_get_current_key_ex(array_hash, &key, &key_len, &index, 0,
&array_pointer) != HASH_KEY_IS_STRING) {
return false;
}
inner_array_hash = Z_ARRVAL_P(*inner_array);
for (zend_hash_internal_pointer_reset_ex(inner_array_hash,
&inner_array_pointer);
zend_hash_get_current_data_ex(inner_array_hash, (void**)&value,
&inner_array_pointer) == SUCCESS;
zend_hash_move_forward_ex(inner_array_hash, &inner_array_pointer)) {
if (Z_TYPE_P(*value) != IS_STRING) {
return false;
}
metadata->metadata[metadata->count].key = key;
metadata->metadata[metadata->count].value = Z_STRVAL_P(*value);
metadata->metadata[metadata->count].value_length = Z_STRLEN_P(*value);
metadata->count += 1;
}
}
return true;
}
/**
* Constructs a new instance of the Call class.
* @param Channel $channel The channel to associate the call with. Must not be
@ -155,9 +226,10 @@ PHP_METHOD(Call, __construct) {
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);
zend_throw_exception(
spl_ce_InvalidArgumentException,
"Call expects a Channel, a String, and a Timeval",
1 TSRMLS_CC);
return;
}
wrapped_grpc_channel *channel =
@ -173,289 +245,238 @@ PHP_METHOD(Call, __construct) {
wrapped_grpc_timeval *deadline =
(wrapped_grpc_timeval *)zend_object_store_get_object(
deadline_obj TSRMLS_CC);
call->wrapped = grpc_channel_create_call_old(
channel->wrapped, method, channel->target, deadline->wrapped);
call->queue = grpc_completion_queue_create();
call->wrapped = grpc_channel_create_call(
channel->wrapped, call->queue, 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
* Start a batch of RPC actions.
* @param array batch Array of actions to take
* @return object Object with results of all actions
*/
PHP_METHOD(Call, add_metadata) {
PHP_METHOD(Call, start_batch) {
wrapped_grpc_call *call =
(wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
grpc_metadata metadata;
grpc_call_error error_code;
grpc_op ops[8];
size_t op_num = 0;
zval *array;
zval **inner_array;
zval **value;
zval **inner_value;
HashTable *array_hash;
HashPosition array_pointer;
HashTable *inner_array_hash;
HashPosition inner_array_pointer;
HashTable *status_hash;
char *key;
uint key_len;
ulong index;
long flags = 0;
/* "a|l" == 1 array, 1 optional long */
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &flags) ==
grpc_metadata_array metadata;
grpc_metadata_array trailing_metadata;
grpc_metadata_array recv_metadata;
grpc_metadata_array recv_trailing_metadata;
grpc_status_code status;
char *status_details = NULL;
size_t status_details_capacity;
grpc_byte_buffer *message;
int cancelled;
grpc_call_error error;
grpc_event *event;
zval *result;
char *message_str;
size_t message_len;
zval *recv_status;
grpc_metadata_array_init(&metadata);
grpc_metadata_array_init(&trailing_metadata);
MAKE_STD_ZVAL(result);
object_init(result);
/* "a" == 1 array */
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &array) ==
FAILURE) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"add_metadata expects an array and an optional long",
1 TSRMLS_CC);
return;
"start_batch expects an array", 1 TSRMLS_CC);
goto cleanup;
}
array_hash = Z_ARRVAL_P(array);
for (zend_hash_internal_pointer_reset_ex(array_hash, &array_pointer);
zend_hash_get_current_data_ex(array_hash, (void**)&inner_array,
zend_hash_get_current_data_ex(array_hash, (void**)&value,
&array_pointer) == SUCCESS;
zend_hash_move_forward_ex(array_hash, &array_pointer)) {
if (zend_hash_get_current_key_ex(array_hash, &key, &key_len, &index, 0,
&array_pointer) != HASH_KEY_IS_STRING) {
&array_pointer) != HASH_KEY_IS_LONG) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"metadata keys must be strings", 1 TSRMLS_CC);
return;
"batch keys must be integers", 1 TSRMLS_CC);
goto cleanup;
}
if (Z_TYPE_P(*inner_array) != IS_ARRAY) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"metadata values must be arrays",
1 TSRMLS_CC);
return;
}
inner_array_hash = Z_ARRVAL_P(*inner_array);
for (zend_hash_internal_pointer_reset_ex(inner_array_hash,
&inner_array_pointer);
zend_hash_get_current_data_ex(inner_array_hash, (void**)&value,
&inner_array_pointer) == SUCCESS;
zend_hash_move_forward_ex(inner_array_hash, &inner_array_pointer)) {
if (Z_TYPE_P(*value) != IS_STRING) {
switch(index) {
case GRPC_OP_SEND_INITIAL_METADATA:
if (!create_metadata_array(*value, &metadata)) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"Bad metadata value given", 1 TSRMLS_CC);
goto cleanup;
}
ops[op_num].data.send_initial_metadata.count =
metadata.count;
ops[op_num].data.send_initial_metadata.metadata =
metadata.metadata;
break;
case GRPC_OP_SEND_MESSAGE:
if (Z_TYPE_PP(value) != IS_STRING) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"Expected a string for send message",
1 TSRMLS_CC);
}
ops[op_num].data.send_message =
string_to_byte_buffer(Z_STRVAL_PP(value), Z_STRLEN_PP(value));
break;
case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
break;
case GRPC_OP_SEND_STATUS_FROM_SERVER:
status_hash = Z_ARRVAL_PP(value);
if (zend_hash_find(status_hash, "metadata", sizeof("metadata"),
(void **)&inner_value) == SUCCESS) {
if (!create_metadata_array(*inner_value, &trailing_metadata)) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"Bad trailing metadata value given",
1 TSRMLS_CC);
goto cleanup;
}
ops[op_num].data.send_status_from_server.trailing_metadata =
trailing_metadata.metadata;
ops[op_num].data.send_status_from_server.trailing_metadata_count =
trailing_metadata.count;
}
if (zend_hash_find(status_hash, "code", sizeof("code"),
(void**)&inner_value) == SUCCESS) {
if (Z_TYPE_PP(inner_value) != IS_LONG) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"Status code must be an integer",
1 TSRMLS_CC);
goto cleanup;
}
ops[op_num].data.send_status_from_server.status =
Z_LVAL_PP(inner_value);
} else {
zend_throw_exception(spl_ce_InvalidArgumentException,
"Integer status code is required",
1 TSRMLS_CC);
goto cleanup;
}
if (zend_hash_find(status_hash, "details", sizeof("details"),
(void**)&inner_value) == SUCCESS) {
if (Z_TYPE_PP(inner_value) != IS_STRING) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"Status details must be a string",
1 TSRMLS_CC);
goto cleanup;
}
ops[op_num].data.send_status_from_server.status_details =
Z_STRVAL_PP(inner_value);
} else {
zend_throw_exception(spl_ce_InvalidArgumentException,
"String status details is required",
1 TSRMLS_CC);
goto cleanup;
}
break;
case GRPC_OP_RECV_INITIAL_METADATA:
ops[op_num].data.recv_initial_metadata = &recv_metadata;
break;
case GRPC_OP_RECV_MESSAGE:
ops[op_num].data.recv_message = &message;
break;
case GRPC_OP_RECV_STATUS_ON_CLIENT:
ops[op_num].data.recv_status_on_client.trailing_metadata =
&recv_trailing_metadata;
ops[op_num].data.recv_status_on_client.status = &status;
ops[op_num].data.recv_status_on_client.status_details =
&status_details;
ops[op_num].data.recv_status_on_client.status_details_capacity =
&status_details_capacity;
break;
case GRPC_OP_RECV_CLOSE_ON_SERVER:
ops[op_num].data.recv_close_on_server.cancelled = &cancelled;
break;
default:
zend_throw_exception(spl_ce_InvalidArgumentException,
"metadata values must be arrays of strings",
1 TSRMLS_CC);
return;
}
metadata.key = key;
metadata.value = Z_STRVAL_P(*value);
metadata.value_length = Z_STRLEN_P(*value);
error_code = grpc_call_add_metadata_old(call->wrapped, &metadata, 0u);
MAYBE_THROW_CALL_ERROR(add_metadata, error_code);
"Unrecognized key in batch", 1 TSRMLS_CC);
goto cleanup;
}
ops[op_num].op = (grpc_op_type)index;
op_num++;
}
}
/**
* 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 $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 Void
*/
PHP_METHOD(Call, invoke) {
grpc_call_error error_code;
long tag1;
long tag2;
zval *queue_obj;
long flags = 0;
/* "Oll|l" == 1 Object, 3 mandatory longs, 1 optional long */
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Oll|l", &queue_obj,
grpc_ce_completion_queue, &tag1, &tag2,
&flags) == FAILURE) {
zend_throw_exception(
spl_ce_InvalidArgumentException,
"invoke needs a CompletionQueue, 2 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);
error_code = grpc_call_invoke_old(call->wrapped, queue->wrapped, (void *)tag1,
(void *)tag2, (gpr_uint32)flags);
MAYBE_THROW_CALL_ERROR(invoke, error_code);
}
/**
* 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 Void
*/
PHP_METHOD(Call, server_accept) {
long tag;
zval *queue_obj;
grpc_call_error error_code;
/* "Ol|l" == 1 Object, 1 long */
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Ol", &queue_obj,
grpc_ce_completion_queue, &tag) == FAILURE) {
zend_throw_exception(
spl_ce_InvalidArgumentException,
"server_accept expects a CompletionQueue, a long, and an optional long",
1 TSRMLS_CC);
return;
error = grpc_call_start_batch(call->wrapped, ops, op_num, NULL);
if (error != GRPC_CALL_OK) {
zend_throw_exception(spl_ce_LogicException,
"start_batch was called incorrectly",
(long)error TSRMLS_CC);
goto cleanup;
}
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);
error_code =
grpc_call_server_accept_old(call->wrapped, queue->wrapped, (void *)tag);
MAYBE_THROW_CALL_ERROR(server_accept, error_code);
}
PHP_METHOD(Call, server_end_initial_metadata) {
grpc_call_error error_code;
long flags = 0;
/* "|l" == 1 optional long */
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &flags) ==
FAILURE) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"server_end_initial_metadata expects an optional long",
event = grpc_completion_queue_pluck(call->queue, NULL, gpr_inf_future);
if (event->data.op_complete != GRPC_OP_OK) {
zend_throw_exception(spl_ce_LogicException,
"The batch failed for some reason",
1 TSRMLS_CC);
goto cleanup;
}
wrapped_grpc_call *call =
(wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
error_code = grpc_call_server_end_initial_metadata_old(call->wrapped, flags);
MAYBE_THROW_CALL_ERROR(server_end_initial_metadata, error_code);
}
/**
* Called by clients to cancel an RPC on the server.
* @return Void
*/
PHP_METHOD(Call, cancel) {
wrapped_grpc_call *call =
(wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
grpc_call_error error_code = grpc_call_cancel(call->wrapped);
MAYBE_THROW_CALL_ERROR(cancel, error_code);
}
/**
* 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 Void
*/
PHP_METHOD(Call, start_write) {
grpc_call_error error_code;
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;
for (int i = 0; i < op_num; i++) {
switch(ops[i].op) {
case GRPC_OP_SEND_INITIAL_METADATA:
add_property_bool(result, "send_metadata", true);
break;
case GRPC_OP_SEND_MESSAGE:
add_property_bool(result, "send_message", true);
break;
case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
add_property_bool(result, "send_close", true);
break;
case GRPC_OP_SEND_STATUS_FROM_SERVER:
add_property_bool(result, "send_status", true);
break;
case GRPC_OP_RECV_INITIAL_METADATA:
add_property_zval(result, "metadata",
grpc_parse_metadata_array(&recv_metadata));
break;
case GRPC_OP_RECV_MESSAGE:
byte_buffer_to_string(message, &message_str, &message_len);
add_property_stringl(result, "message", message_str, message_len,
false);
break;
case GRPC_OP_RECV_STATUS_ON_CLIENT:
MAKE_STD_ZVAL(recv_status);
object_init(recv_status);
add_property_zval(recv_status, "metadata",
grpc_parse_metadata_array(&recv_trailing_metadata));
add_property_long(recv_status, "code", status);
add_property_string(recv_status, "details", status_details, false);
add_property_zval(result, "status", recv_status);
break;
case GRPC_OP_RECV_CLOSE_ON_SERVER:
add_property_bool(result, "cancelled", cancelled);
break;
default:
break;
}
}
error_code = grpc_call_start_write_old(
call->wrapped, string_to_byte_buffer(buffer, buffer_len), (void *)tag,
(gpr_uint32)flags);
MAYBE_THROW_CALL_ERROR(start_write, error_code);
}
/**
* 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 Void
*/
PHP_METHOD(Call, start_write_status) {
grpc_call_error error_code;
wrapped_grpc_call *call =
(wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
long status_code;
int status_details_length;
long tag;
char *status_details;
/* "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;
cleanup:
if (metadata.metadata != NULL) {
gpr_free(metadata.metadata);
}
error_code = grpc_call_start_write_status_old(call->wrapped,
(grpc_status_code)status_code,
status_details, (void *)tag);
MAYBE_THROW_CALL_ERROR(start_write_status, error_code);
}
/**
* Indicate that there are no more messages to send
* @return Void
*/
PHP_METHOD(Call, writes_done) {
grpc_call_error error_code;
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;
grpc_metadata_array_destroy(&metadata);
if (trailing_metadata.metadata != NULL) {
gpr_free(trailing_metadata.metadata);
}
error_code = grpc_call_writes_done_old(call->wrapped, (void *)tag);
MAYBE_THROW_CALL_ERROR(writes_done, error_code);
}
/**
* 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 Void
*/
PHP_METHOD(Call, start_read) {
grpc_call_error error_code;
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;
grpc_metadata_array_destroy(&trailing_metadata);
grpc_metadata_array_destroy(&recv_metadata);
grpc_metadata_array_destroy(&recv_trailing_metadata);
if (status_details != NULL) {
gpr_free(status_details);
}
error_code = grpc_call_start_read_old(call->wrapped, (void *)tag);
MAYBE_THROW_CALL_ERROR(start_read, error_code);
RETURN_DESTROY_ZVAL(result);
}
static zend_function_entry call_methods[] = {
PHP_ME(Call, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
PHP_ME(Call, server_accept, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Call, server_end_initial_metadata, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Call, add_metadata, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Call, cancel, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Call, 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};
PHP_ME(Call, start_batch, NULL, ZEND_ACC_PUBLIC) PHP_FE_END};
void grpc_init_call(TSRMLS_D) {
zend_class_entry ce;

@ -45,17 +45,6 @@
#include "grpc/grpc.h"
// Throw an exception if error_code is not OK
#define MAYBE_THROW_CALL_ERROR(func_name, error_code) \
do { \
if (error_code != GRPC_CALL_OK) { \
zend_throw_exception(spl_ce_LogicException, \
#func_name " was called incorrectly", \
(long)error_code TSRMLS_CC); \
return; \
} \
} while (0)
/* Class entry for the Call PHP class */
zend_class_entry *grpc_ce_call;
@ -65,6 +54,7 @@ typedef struct wrapped_grpc_call {
bool owned;
grpc_call *wrapped;
grpc_completion_queue *queue;
} wrapped_grpc_call;
/* Initializes the Call PHP class */
@ -75,6 +65,6 @@ zval *grpc_php_wrap_call(grpc_call *wrapped, bool owned);
/* Creates and returns a PHP associative array of metadata from a C array of
* call metadata */
zval *grpc_call_create_metadata_array(int count, grpc_metadata *elements);
zval *grpc_parse_metadata_array(grpc_metadata_array *metadata_array);
#endif /* NET_GRPC_PHP_GRPC_CHANNEL_H_ */

@ -51,7 +51,6 @@
#include "grpc/support/log.h"
#include "grpc/grpc_security.h"
#include "completion_queue.h"
#include "server.h"
#include "credentials.h"

@ -1,168 +0,0 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "completion_queue.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 <stdbool.h>
#include "grpc/grpc.h"
#include "event.h"
#include "timeval.h"
/* Frees and destroys a wrapped instance of grpc_completion_queue */
void free_wrapped_grpc_completion_queue(void *object TSRMLS_DC) {
wrapped_grpc_completion_queue *queue = NULL;
grpc_event *event;
queue = (wrapped_grpc_completion_queue *)object;
if (queue->wrapped != NULL) {
grpc_completion_queue_shutdown(queue->wrapped);
event = grpc_completion_queue_next(queue->wrapped, gpr_inf_future);
while (event != NULL) {
if (event->type == GRPC_QUEUE_SHUTDOWN) {
break;
}
event = grpc_completion_queue_next(queue->wrapped, gpr_inf_future);
}
grpc_completion_queue_destroy(queue->wrapped);
}
efree(queue);
}
/* Initializes an instance of wrapped_grpc_channel to be associated with an
* object of a class specified by class_type */
zend_object_value create_wrapped_grpc_completion_queue(
zend_class_entry *class_type TSRMLS_DC) {
zend_object_value retval;
wrapped_grpc_completion_queue *intern;
intern = (wrapped_grpc_completion_queue *)emalloc(
sizeof(wrapped_grpc_completion_queue));
memset(intern, 0, sizeof(wrapped_grpc_completion_queue));
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_completion_queue, NULL TSRMLS_CC);
retval.handlers = zend_get_std_object_handlers();
return retval;
}
/**
* Construct an instance of CompletionQueue
*/
PHP_METHOD(CompletionQueue, __construct) {
wrapped_grpc_completion_queue *queue =
(wrapped_grpc_completion_queue *)zend_object_store_get_object(getThis()
TSRMLS_CC);
queue->wrapped = grpc_completion_queue_create();
}
/**
* Blocks until an event is available, the completion queue is being shutdown,
* or timeout is reached. Returns NULL on timeout, otherwise the event that
* occurred. Callers should call event.finish once they have processed the
* event.
* @param Timeval $timeout The timeout for the event
* @return Event The event that occurred
*/
PHP_METHOD(CompletionQueue, next) {
zval *timeout;
/* "O" == 1 Object */
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &timeout,
grpc_ce_timeval) == FAILURE) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"next needs a Timeval", 1 TSRMLS_CC);
return;
}
wrapped_grpc_completion_queue *completion_queue =
(wrapped_grpc_completion_queue *)zend_object_store_get_object(getThis()
TSRMLS_CC);
wrapped_grpc_timeval *wrapped_timeout =
(wrapped_grpc_timeval *)zend_object_store_get_object(timeout TSRMLS_CC);
grpc_event *event = grpc_completion_queue_next(completion_queue->wrapped,
wrapped_timeout->wrapped);
if (event == NULL) {
RETURN_NULL();
}
zval *wrapped_event = grpc_php_convert_event(event);
RETURN_DESTROY_ZVAL(wrapped_event);
}
PHP_METHOD(CompletionQueue, pluck) {
long tag;
zval *timeout;
/* "lO" == 1 long, 1 Object */
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lO", &tag, &timeout,
grpc_ce_timeval) == FAILURE) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"pluck needs a long and a Timeval", 1 TSRMLS_CC);
}
wrapped_grpc_completion_queue *completion_queue =
(wrapped_grpc_completion_queue *)zend_object_store_get_object(getThis()
TSRMLS_CC);
wrapped_grpc_timeval *wrapped_timeout =
(wrapped_grpc_timeval *)zend_object_store_get_object(timeout TSRMLS_CC);
grpc_event *event = grpc_completion_queue_pluck(
completion_queue->wrapped, (void *)tag, wrapped_timeout->wrapped);
if (event == NULL) {
RETURN_NULL();
}
zval *wrapped_event = grpc_php_convert_event(event);
RETURN_DESTROY_ZVAL(wrapped_event);
}
static zend_function_entry completion_queue_methods[] = {
PHP_ME(CompletionQueue, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
PHP_ME(CompletionQueue, next, NULL, ZEND_ACC_PUBLIC)
PHP_ME(CompletionQueue, pluck, NULL, ZEND_ACC_PUBLIC) PHP_FE_END};
void grpc_init_completion_queue(TSRMLS_D) {
zend_class_entry ce;
INIT_CLASS_ENTRY(ce, "Grpc\\CompletionQueue", completion_queue_methods);
ce.create_object = create_wrapped_grpc_completion_queue;
grpc_ce_completion_queue = zend_register_internal_class(&ce TSRMLS_CC);
}

@ -1,62 +0,0 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef NET_GRPC_PHP_GRPC_COMPLETION_QUEUE_H_
#define NET_GRPC_PHP_GRPC_COMPLETION_QUEUE_H_
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
#include "php_grpc.h"
#include "grpc/grpc.h"
/* Class entry for the PHP CompletionQueue class */
zend_class_entry *grpc_ce_completion_queue;
/* Wrapper class for grpc_completion_queue that can be associated with a
PHP object */
typedef struct wrapped_grpc_completion_queue {
zend_object std;
grpc_completion_queue *wrapped;
} wrapped_grpc_completion_queue;
/* Initialize the CompletionQueue class */
void grpc_init_completion_queue(TSRMLS_D);
#endif /* NET_GRPC_PHP_GRPC_COMPLETION_QUEUE_H_ */

@ -66,5 +66,5 @@ if test "$PHP_GRPC" != "no"; then
PHP_SUBST(GRPC_SHARED_LIBADD)
PHP_NEW_EXTENSION(grpc, byte_buffer.c call.c channel.c completion_queue.c credentials.c event.c timeval.c server.c server_credentials.c php_grpc.c, $ext_shared, , -Wall -Werror -pedantic -std=c99)
PHP_NEW_EXTENSION(grpc, byte_buffer.c call.c channel.c credentials.c timeval.c server.c server_credentials.c php_grpc.c, $ext_shared, , -Wall -Werror -pedantic -std=c99)
fi

@ -1,150 +0,0 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "event.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
#include "php_grpc.h"
#include <stdbool.h>
#include "grpc/grpc.h"
#include "byte_buffer.h"
#include "call.h"
#include "timeval.h"
/* Create a new PHP object containing the event data in the event struct.
event must not be used after this function is called */
zval *grpc_php_convert_event(grpc_event *event) {
zval *data_object;
char *detail_string;
size_t detail_len;
char *method_string;
size_t method_len;
char *host_string;
size_t host_len;
char *read_string;
size_t read_len;
zval *event_object;
if (event == NULL) {
return NULL;
}
MAKE_STD_ZVAL(event_object);
object_init(event_object);
add_property_zval(
event_object, "call",
grpc_php_wrap_call(event->call, event->type == GRPC_SERVER_RPC_NEW));
add_property_long(event_object, "type", event->type);
add_property_long(event_object, "tag", (long)event->tag);
switch (event->type) {
case GRPC_QUEUE_SHUTDOWN:
add_property_null(event_object, "data");
break;
case GRPC_READ:
if (event->data.read == NULL) {
add_property_null(event_object, "data");
} else {
byte_buffer_to_string(event->data.read, &read_string, &read_len);
add_property_stringl(event_object, "data", read_string, read_len, true);
}
break;
case GRPC_WRITE_ACCEPTED:
add_property_long(event_object, "data", (long)event->data.write_accepted);
break;
case GRPC_FINISH_ACCEPTED:
add_property_long(event_object, "data",
(long)event->data.finish_accepted);
break;
case GRPC_CLIENT_METADATA_READ:
data_object = grpc_call_create_metadata_array(
event->data.client_metadata_read.count,
event->data.client_metadata_read.elements);
add_property_zval(event_object, "data", data_object);
break;
case GRPC_FINISHED:
MAKE_STD_ZVAL(data_object);
object_init(data_object);
add_property_long(data_object, "code", event->data.finished.status);
if (event->data.finished.details == NULL) {
add_property_null(data_object, "details");
} else {
detail_len = strlen(event->data.finished.details);
detail_string = ecalloc(detail_len + 1, sizeof(char));
memcpy(detail_string, event->data.finished.details, detail_len);
add_property_string(data_object, "details", detail_string, true);
}
add_property_zval(data_object, "metadata",
grpc_call_create_metadata_array(
event->data.finished.metadata_count,
event->data.finished.metadata_elements));
add_property_zval(event_object, "data", data_object);
break;
case GRPC_SERVER_RPC_NEW:
MAKE_STD_ZVAL(data_object);
object_init(data_object);
method_len = strlen(event->data.server_rpc_new.method);
method_string = ecalloc(method_len + 1, sizeof(char));
memcpy(method_string, event->data.server_rpc_new.method, method_len);
add_property_string(data_object, "method", method_string, false);
host_len = strlen(event->data.server_rpc_new.host);
host_string = ecalloc(host_len + 1, sizeof(char));
memcpy(host_string, event->data.server_rpc_new.host, host_len);
add_property_string(data_object, "host", host_string, false);
add_property_zval(
data_object, "absolute_timeout",
grpc_php_wrap_timeval(event->data.server_rpc_new.deadline));
add_property_zval(data_object, "metadata",
grpc_call_create_metadata_array(
event->data.server_rpc_new.metadata_count,
event->data.server_rpc_new.metadata_elements));
add_property_zval(event_object, "data", data_object);
break;
default:
add_property_null(event_object, "data");
break;
}
grpc_event_finish(event);
return event_object;
}

@ -1,51 +0,0 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef NET_GRPC_PHP_GRPC_EVENT_H_
#define NET_GRPC_PHP_GRPC_EVENT_H_
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
#include "php_grpc.h"
#include "grpc/grpc.h"
/* Create a new Event object that wraps an existing grpc_event struct */
zval *grpc_php_convert_event(grpc_event *event);
#endif /* NET_GRPC_PHP_GRPC_COMPLETION_CHANNEL_H */

@ -34,8 +34,6 @@
#include "call.h"
#include "channel.h"
#include "server.h"
#include "completion_queue.h"
#include "event.h"
#include "timeval.h"
#include "credentials.h"
#include "server_credentials.h"
@ -127,27 +125,12 @@ PHP_MINIT_FUNCTION(grpc) {
REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR_INVALID_FLAGS",
GRPC_CALL_ERROR_INVALID_FLAGS, CONST_CS);
/* Register op error constants */
REGISTER_LONG_CONSTANT("Grpc\\OP_OK", GRPC_OP_OK, CONST_CS);
REGISTER_LONG_CONSTANT("Grpc\\OP_ERROR", GRPC_OP_ERROR, CONST_CS);
/* Register flag constants */
REGISTER_LONG_CONSTANT("Grpc\\WRITE_BUFFER_HINT", GRPC_WRITE_BUFFER_HINT,
CONST_CS);
REGISTER_LONG_CONSTANT("Grpc\\WRITE_NO_COMPRESS", GRPC_WRITE_NO_COMPRESS,
CONST_CS);
/* Register completion type constants */
REGISTER_LONG_CONSTANT("Grpc\\QUEUE_SHUTDOWN", GRPC_QUEUE_SHUTDOWN, CONST_CS);
REGISTER_LONG_CONSTANT("Grpc\\READ", GRPC_READ, CONST_CS);
REGISTER_LONG_CONSTANT("Grpc\\FINISH_ACCEPTED", GRPC_FINISH_ACCEPTED,
CONST_CS);
REGISTER_LONG_CONSTANT("Grpc\\WRITE_ACCEPTED", GRPC_WRITE_ACCEPTED, CONST_CS);
REGISTER_LONG_CONSTANT("Grpc\\CLIENT_METADATA_READ",
GRPC_CLIENT_METADATA_READ, CONST_CS);
REGISTER_LONG_CONSTANT("Grpc\\FINISHED", GRPC_FINISHED, CONST_CS);
REGISTER_LONG_CONSTANT("Grpc\\SERVER_RPC_NEW", GRPC_SERVER_RPC_NEW, CONST_CS);
/* Register status constants */
REGISTER_LONG_CONSTANT("Grpc\\STATUS_OK", GRPC_STATUS_OK, CONST_CS);
REGISTER_LONG_CONSTANT("Grpc\\STATUS_CANCELLED", GRPC_STATUS_CANCELLED,
@ -181,10 +164,27 @@ PHP_MINIT_FUNCTION(grpc) {
REGISTER_LONG_CONSTANT("Grpc\\STATUS_DATA_LOSS", GRPC_STATUS_DATA_LOSS,
CONST_CS);
/* Register op type constants */
REGISTER_LONG_CONSTANT("Grpc\\OP_SEND_INITIAL_METADATA",
GRPC_OP_SEND_INITIAL_METADATA, CONST_CS);
REGISTER_LONG_CONSTANT("Grpc\\OP_SEND_MESSAGE",
GRPC_OP_SEND_MESSAGE, CONST_CS);
REGISTER_LONG_CONSTANT("Grpc\\OP_SEND_CLOSE_FROM_CLIENT",
GRPC_OP_SEND_CLOSE_FROM_CLIENT, CONST_CS);
REGISTER_LONG_CONSTANT("Grpc\\OP_SEND_STATUS_FROM_SERVER",
GRPC_OP_SEND_STATUS_FROM_SERVER, CONST_CS);
REGISTER_LONG_CONSTANT("Grpc\\OP_RECV_INITIAL_METADATA",
GRPC_OP_RECV_INITIAL_METADATA, CONST_CS);
REGISTER_LONG_CONSTANT("Grpc\\OP_RECV_MESSAGE",
GRPC_OP_RECV_MESSAGE, CONST_CS);
REGISTER_LONG_CONSTANT("Grpc\\OP_RECV_STATUS_ON_CLIENT",
GRPC_OP_RECV_STATUS_ON_CLIENT, CONST_CS);
REGISTER_LONG_CONSTANT("Grpc\\OP_RECV_CLOSE_ON_SERVER",
GRPC_OP_RECV_CLOSE_ON_SERVER, CONST_CS);
grpc_init_call(TSRMLS_C);
grpc_init_channel(TSRMLS_C);
grpc_init_server(TSRMLS_C);
grpc_init_completion_queue(TSRMLS_C);
grpc_init_timeval(TSRMLS_C);
grpc_init_credentials(TSRMLS_C);
grpc_init_server_credentials(TSRMLS_C);

@ -52,13 +52,25 @@
#include "grpc/grpc_security.h"
#include "server.h"
#include "completion_queue.h"
#include "channel.h"
#include "server_credentials.h"
#include "timeval.h"
/* Frees and destroys an instance of wrapped_grpc_server */
void free_wrapped_grpc_server(void *object TSRMLS_DC) {
wrapped_grpc_server *server = (wrapped_grpc_server *)object;
grpc_event *event;
if (server->queue != NULL) {
grpc_completion_queue_shutdown(server->queue);
event = grpc_completion_queue_next(server->queue, gpr_inf_future);
while (event != NULL) {
if (event->type == GRPC_QUEUE_SHUTDOWN) {
break;
}
event = grpc_completion_queue_next(server->queue, gpr_inf_future);
}
grpc_completion_queue_destroy(server->queue);
}
if (server->wrapped != NULL) {
grpc_server_shutdown(server->wrapped);
grpc_server_destroy(server->wrapped);
@ -93,26 +105,22 @@ zend_object_value create_wrapped_grpc_server(zend_class_entry *class_type
PHP_METHOD(Server, __construct) {
wrapped_grpc_server *server =
(wrapped_grpc_server *)zend_object_store_get_object(getThis() TSRMLS_CC);
zval *queue_obj;
zval *args_array = NULL;
grpc_channel_args args;
HashTable *array_hash;
zval **creds_obj = NULL;
wrapped_grpc_server_credentials *creds = NULL;
/* "O|a" == 1 Object, 1 optional array */
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|a", &queue_obj,
grpc_ce_completion_queue, &args_array) == FAILURE) {
/* "a" == 1 optional array */
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &args_array) ==
FAILURE) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"Server expects a CompletionQueue and an array",
"Server expects an array",
1 TSRMLS_CC);
return;
}
add_property_zval(getThis(), "completion_queue", queue_obj);
wrapped_grpc_completion_queue *queue =
(wrapped_grpc_completion_queue *)zend_object_store_get_object(
queue_obj TSRMLS_CC);
server->queue = grpc_completion_queue_create();
if (args_array == NULL) {
server->wrapped = grpc_server_create(queue->wrapped, NULL);
server->wrapped = grpc_server_create(server->queue, NULL);
} else {
array_hash = Z_ARRVAL_P(args_array);
if (zend_hash_find(array_hash, "credentials", sizeof("credentials"),
@ -130,11 +138,11 @@ PHP_METHOD(Server, __construct) {
}
php_grpc_read_args_array(args_array, &args);
if (creds == NULL) {
server->wrapped = grpc_server_create(queue->wrapped, &args);
server->wrapped = grpc_server_create(server->queue, &args);
} else {
gpr_log(GPR_DEBUG, "Initialized secure server");
server->wrapped =
grpc_secure_server_create(creds->wrapped, queue->wrapped, &args);
grpc_secure_server_create(creds->wrapped, server->queue, &args);
}
efree(args.args);
}
@ -150,16 +158,39 @@ PHP_METHOD(Server, request_call) {
grpc_call_error error_code;
wrapped_grpc_server *server =
(wrapped_grpc_server *)zend_object_store_get_object(getThis() TSRMLS_CC);
long tag_new;
/* "l" == 1 long */
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &tag_new) ==
FAILURE) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"request_call expects a long", 1 TSRMLS_CC);
return;
grpc_call *call;
grpc_call_details details;
grpc_metadata_array metadata;
zval *result;
grpc_event *event;
MAKE_STD_ZVAL(result);
object_init(result);
grpc_call_details_init(&details);
grpc_metadata_array_init(&metadata);
error_code = grpc_server_request_call(server->wrapped, &call, &details,
&metadata, server->queue, NULL);
if (error_code != GRPC_CALL_OK) {
zend_throw_exception(spl_ce_LogicException, "request_call failed",
(long)error_code TSRMLS_CC);
goto cleanup;
}
event = grpc_completion_queue_pluck(server->queue, NULL, gpr_inf_future);
if (event->data.op_complete != GRPC_OP_OK) {
zend_throw_exception(spl_ce_LogicException,
"Failed to request a call for some reason",
1 TSRMLS_CC);
goto cleanup;
}
error_code = grpc_server_request_call_old(server->wrapped, (void *)tag_new);
MAYBE_THROW_CALL_ERROR(request_call, error_code);
add_property_zval(result, "call", grpc_php_wrap_call(call, true));
add_property_string(result, "method", details.method, false);
add_property_string(result, "host", details.host, false);
add_property_zval(result, "absolute_deadline",
grpc_php_wrap_timeval(details.deadline));
add_property_zval(result, "metadata", grpc_parse_metadata_array(&metadata));
cleanup:
grpc_call_details_destroy(&details);
grpc_metadata_array_destroy(&metadata);
RETURN_DESTROY_ZVAL(result);
}
/**

@ -53,6 +53,7 @@ typedef struct wrapped_grpc_server {
zend_object std;
grpc_server *wrapped;
grpc_completion_queue *queue;
} wrapped_grpc_server;
/* Initializes the Server class */

Loading…
Cancel
Save