blob: 6c432d2818744a8c6d230db9920f730ec65b7bbf [file] [log] [blame]
Craig Tiller1a61b172015-02-16 11:53:47 -08001/*
2 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02003 * Copyright 2015 gRPC authors.
Craig Tiller1a61b172015-02-16 11:53:47 -08004 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02005 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
Craig Tiller1a61b172015-02-16 11:53:47 -08008 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02009 * http://www.apache.org/licenses/LICENSE-2.0
Craig Tiller1a61b172015-02-16 11:53:47 -080010 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +020011 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
Craig Tiller1a61b172015-02-16 11:53:47 -080016 *
17 */
18
mlumishb892a272014-12-09 16:28:23 -080019#include "channel.h"
20
21#ifdef HAVE_CONFIG_H
22#include "config.h"
23#endif
24
murgatroid998242ba72015-04-01 15:29:44 -070025#include <php.h>
26#include <php_ini.h>
27#include <ext/standard/info.h>
28#include <ext/spl/spl_exceptions.h>
mlumishb892a272014-12-09 16:28:23 -080029#include "php_grpc.h"
30
murgatroid998242ba72015-04-01 15:29:44 -070031#include <zend_exceptions.h>
mlumishb892a272014-12-09 16:28:23 -080032
33#include <stdbool.h>
34
murgatroid998242ba72015-04-01 15:29:44 -070035#include <grpc/grpc.h>
murgatroid998242ba72015-04-01 15:29:44 -070036#include <grpc/grpc_security.h>
mlumishb892a272014-12-09 16:28:23 -080037
Stanley Cheunga63fdd02015-08-11 15:11:11 -070038#include "completion_queue.h"
Stanley Cheung9c0b35e2015-10-21 17:07:56 -070039#include "channel_credentials.h"
Stanley Cheunga63fdd02015-08-11 15:11:11 -070040#include "server.h"
41#include "timeval.h"
mlumishb892a272014-12-09 16:28:23 -080042
Xiaoguang Sun8a929a92015-03-13 14:22:31 +080043zend_class_entry *grpc_ce_channel;
thinkeroudba5b0c2016-07-27 18:39:16 +080044#if PHP_MAJOR_VERSION >= 7
45static zend_object_handlers channel_ce_handlers;
46#endif
Xiaoguang Sun8a929a92015-03-13 14:22:31 +080047
mlumishb892a272014-12-09 16:28:23 -080048/* Frees and destroys an instance of wrapped_grpc_channel */
thinkerou011d1ef2016-07-27 09:44:49 +080049PHP_GRPC_FREE_WRAPPED_FUNC_START(wrapped_grpc_channel)
50 if (p->wrapped != NULL) {
51 grpc_channel_destroy(p->wrapped);
mlumishb892a272014-12-09 16:28:23 -080052 }
thinkerou011d1ef2016-07-27 09:44:49 +080053PHP_GRPC_FREE_WRAPPED_FUNC_END()
54
mlumishb892a272014-12-09 16:28:23 -080055/* Initializes an instance of wrapped_grpc_channel to be associated with an
56 * object of a class specified by class_type */
thinkeroudba5b0c2016-07-27 18:39:16 +080057php_grpc_zend_object create_wrapped_grpc_channel(zend_class_entry *class_type
58 TSRMLS_DC) {
thinkerouba75c012016-07-28 02:30:08 +080059 PHP_GRPC_ALLOC_CLASS_OBJECT(wrapped_grpc_channel);
mlumishb892a272014-12-09 16:28:23 -080060 zend_object_std_init(&intern->std, class_type TSRMLS_CC);
61 object_properties_init(&intern->std, class_type);
thinkeroudc673c52016-07-28 09:49:38 +080062 PHP_GRPC_FREE_CLASS_OBJECT(wrapped_grpc_channel, channel_ce_handlers);
thinkeroudba5b0c2016-07-27 18:39:16 +080063}
thinkerou6f9d30b2016-07-27 03:19:03 +080064
Stanley Cheungbae0cf12016-07-20 14:02:33 -070065void php_grpc_read_args_array(zval *args_array,
66 grpc_channel_args *args TSRMLS_DC) {
mlumishb892a272014-12-09 16:28:23 -080067 HashTable *array_hash;
mlumishb892a272014-12-09 16:28:23 -080068 int args_index;
mlumishb892a272014-12-09 16:28:23 -080069 array_hash = Z_ARRVAL_P(args_array);
thinkerou6f9d30b2016-07-27 03:19:03 +080070 if (!array_hash) {
71 zend_throw_exception(spl_ce_InvalidArgumentException,
Stanley Cheungc1f25fb2016-07-29 13:41:22 -070072 "array_hash is NULL", 1 TSRMLS_CC);
thinkerou6f9d30b2016-07-27 03:19:03 +080073 return;
74 }
mlumishb892a272014-12-09 16:28:23 -080075 args->num_args = zend_hash_num_elements(array_hash);
76 args->args = ecalloc(args->num_args, sizeof(grpc_arg));
77 args_index = 0;
thinkerou6f9d30b2016-07-27 03:19:03 +080078
thinkerouba75c012016-07-28 02:30:08 +080079 char *key = NULL;
80 zval *data;
81 int key_type;
82
83 PHP_GRPC_HASH_FOREACH_STR_KEY_VAL_START(array_hash, key, key_type, data)
84 if (key_type != HASH_KEY_IS_STRING) {
mlumishb892a272014-12-09 16:28:23 -080085 zend_throw_exception(spl_ce_InvalidArgumentException,
Craig Tillerb5dcec52015-01-13 11:13:42 -080086 "args keys must be strings", 1 TSRMLS_CC);
mlumishb892a272014-12-09 16:28:23 -080087 return;
88 }
89 args->args[args_index].key = key;
thinkeroua3730b72016-07-20 16:59:54 +080090 switch (Z_TYPE_P(data)) {
91 case IS_LONG:
92 args->args[args_index].value.integer = (int)Z_LVAL_P(data);
93 args->args[args_index].type = GRPC_ARG_INTEGER;
94 break;
95 case IS_STRING:
96 args->args[args_index].value.string = Z_STRVAL_P(data);
97 args->args[args_index].type = GRPC_ARG_STRING;
98 break;
99 default:
100 zend_throw_exception(spl_ce_InvalidArgumentException,
thinkerouba75c012016-07-28 02:30:08 +0800101 "args values must be int or string", 1 TSRMLS_CC);
thinkeroua3730b72016-07-20 16:59:54 +0800102 return;
103 }
104 args_index++;
thinkerouba75c012016-07-28 02:30:08 +0800105 PHP_GRPC_HASH_FOREACH_END()
thinkerou6f9d30b2016-07-27 03:19:03 +0800106}
thinkeroua3730b72016-07-20 16:59:54 +0800107
mlumishb892a272014-12-09 16:28:23 -0800108/**
109 * Construct an instance of the Channel class. If the $args array contains a
Stanley Cheung9c0b35e2015-10-21 17:07:56 -0700110 * "credentials" key mapping to a ChannelCredentials object, a secure channel
111 * will be created with those credentials.
mlumishb892a272014-12-09 16:28:23 -0800112 * @param string $target The hostname to associate with this channel
thinkerouefbc9e72016-08-16 20:00:36 +0800113 * @param array $args_array The arguments to pass to the Channel
mlumishb892a272014-12-09 16:28:23 -0800114 */
Craig Tillerb5dcec52015-01-13 11:13:42 -0800115PHP_METHOD(Channel, __construct) {
thinkeroua3730b72016-07-20 16:59:54 +0800116 wrapped_grpc_channel *channel = Z_WRAPPED_GRPC_CHANNEL_P(getThis());
117 zval *creds_obj = NULL;
thinkeroua3730b72016-07-20 16:59:54 +0800118 char *target;
thinkerou19304682016-07-22 02:43:19 +0800119 php_grpc_int target_length;
mlumishb892a272014-12-09 16:28:23 -0800120 zval *args_array = NULL;
121 grpc_channel_args args;
122 HashTable *array_hash;
Stanley Cheungaeea1022015-10-21 17:00:49 -0700123 wrapped_grpc_channel_credentials *creds = NULL;
thinkeroua3730b72016-07-20 16:59:54 +0800124
Stanley Cheungf77a4ad2016-02-16 09:45:51 -0800125 /* "sa" == 1 string, 1 array */
126 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa", &target,
Craig Tillerb5dcec52015-01-13 11:13:42 -0800127 &target_length, &args_array) == FAILURE) {
mlumishb892a272014-12-09 16:28:23 -0800128 zend_throw_exception(spl_ce_InvalidArgumentException,
Craig Tillerb5dcec52015-01-13 11:13:42 -0800129 "Channel expects a string and an array", 1 TSRMLS_CC);
mlumishb892a272014-12-09 16:28:23 -0800130 return;
131 }
Stanley Cheungcccf9292016-02-12 16:37:19 -0800132 array_hash = Z_ARRVAL_P(args_array);
thinkerouba75c012016-07-28 02:30:08 +0800133 if (php_grpc_zend_hash_find(array_hash, "credentials", sizeof("credentials"),
Stanley Cheungcccf9292016-02-12 16:37:19 -0800134 (void **)&creds_obj) == SUCCESS) {
thinkerouba75c012016-07-28 02:30:08 +0800135 if (Z_TYPE_P(creds_obj) == IS_NULL) {
Stanley Cheungcccf9292016-02-12 16:37:19 -0800136 creds = NULL;
thinkerouba75c012016-07-28 02:30:08 +0800137 php_grpc_zend_hash_del(array_hash, "credentials", sizeof("credentials"));
138 } else if (PHP_GRPC_GET_CLASS_ENTRY(creds_obj) !=
139 grpc_ce_channel_credentials) {
Stanley Cheungcccf9292016-02-12 16:37:19 -0800140 zend_throw_exception(spl_ce_InvalidArgumentException,
141 "credentials must be a ChannelCredentials object",
142 1 TSRMLS_CC);
143 return;
mlumishb892a272014-12-09 16:28:23 -0800144 } else {
thinkeroua3730b72016-07-20 16:59:54 +0800145 creds = Z_WRAPPED_GRPC_CHANNEL_CREDS_P(creds_obj);
thinkerouba75c012016-07-28 02:30:08 +0800146 php_grpc_zend_hash_del(array_hash, "credentials", sizeof("credentials"));
thinkeroua3730b72016-07-20 16:59:54 +0800147 }
148 }
Michael Bausor4f8e40b2016-05-16 11:41:25 -0700149 php_grpc_read_args_array(args_array, &args TSRMLS_CC);
Stanley Cheungcccf9292016-02-12 16:37:19 -0800150 if (creds == NULL) {
151 channel->wrapped = grpc_insecure_channel_create(target, &args, NULL);
152 } else {
Stanley Cheungcccf9292016-02-12 16:37:19 -0800153 channel->wrapped =
154 grpc_secure_channel_create(creds->wrapped, target, &args, NULL);
155 }
156 efree(args.args);
mlumishb892a272014-12-09 16:28:23 -0800157}
158
159/**
Stanley Cheungdb98e082015-07-27 10:19:45 -0700160 * Get the endpoint this call/stream is connected to
161 * @return string The URI of the endpoint
162 */
163PHP_METHOD(Channel, getTarget) {
thinkeroua3730b72016-07-20 16:59:54 +0800164 wrapped_grpc_channel *channel = Z_WRAPPED_GRPC_CHANNEL_P(getThis());
thinkerou19304682016-07-22 02:43:19 +0800165 PHP_GRPC_RETURN_STRING(grpc_channel_get_target(channel->wrapped), 1);
Stanley Cheungdb98e082015-07-27 10:19:45 -0700166}
167
168/**
Stanley Cheunge63354a2015-08-10 15:46:42 -0700169 * Get the connectivity state of the channel
thinkerouefbc9e72016-08-16 20:00:36 +0800170 * @param bool $try_to_connect Try to connect on the channel (optional)
Stanley Cheunge63354a2015-08-10 15:46:42 -0700171 * @return long The grpc connectivity state
172 */
173PHP_METHOD(Channel, getConnectivityState) {
thinkeroua3730b72016-07-20 16:59:54 +0800174 wrapped_grpc_channel *channel = Z_WRAPPED_GRPC_CHANNEL_P(getThis());
thinkeroua3730b72016-07-20 16:59:54 +0800175 bool try_to_connect = false;
176
Stanley Cheunge63354a2015-08-10 15:46:42 -0700177 /* "|b" == 1 optional bool */
thinkeroua3730b72016-07-20 16:59:54 +0800178 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &try_to_connect)
179 == FAILURE) {
Stanley Cheunge63354a2015-08-10 15:46:42 -0700180 zend_throw_exception(spl_ce_InvalidArgumentException,
181 "getConnectivityState expects a bool", 1 TSRMLS_CC);
182 return;
183 }
184 RETURN_LONG(grpc_channel_check_connectivity_state(channel->wrapped,
185 (int)try_to_connect));
186}
187
188/**
Stanley Cheunga63fdd02015-08-11 15:11:11 -0700189 * Watch the connectivity state of the channel until it changed
thinkerouefbc9e72016-08-16 20:00:36 +0800190 * @param long $last_state The previous connectivity state of the channel
191 * @param Timeval $deadline_obj The deadline this function should wait until
Stanley Cheung4c5c7b82015-08-12 16:28:58 -0700192 * @return bool If the connectivity state changes from last_state
193 * before deadline
Stanley Cheunga63fdd02015-08-11 15:11:11 -0700194 */
195PHP_METHOD(Channel, watchConnectivityState) {
thinkeroua3730b72016-07-20 16:59:54 +0800196 wrapped_grpc_channel *channel = Z_WRAPPED_GRPC_CHANNEL_P(getThis());
thinkerou19304682016-07-22 02:43:19 +0800197 php_grpc_long last_state;
Stanley Cheunga63fdd02015-08-11 15:11:11 -0700198 zval *deadline_obj;
thinkeroua3730b72016-07-20 16:59:54 +0800199
Stanley Cheunga63fdd02015-08-11 15:11:11 -0700200 /* "lO" == 1 long 1 object */
201 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lO",
202 &last_state, &deadline_obj, grpc_ce_timeval) == FAILURE) {
203 zend_throw_exception(spl_ce_InvalidArgumentException,
thinkerouba75c012016-07-28 02:30:08 +0800204 "watchConnectivityState expects 1 long 1 timeval", 1 TSRMLS_CC);
Stanley Cheunga63fdd02015-08-11 15:11:11 -0700205 return;
206 }
207
thinkeroua3730b72016-07-20 16:59:54 +0800208 wrapped_grpc_timeval *deadline = Z_WRAPPED_GRPC_TIMEVAL_P(deadline_obj);
thinkeroua3730b72016-07-20 16:59:54 +0800209 grpc_channel_watch_connectivity_state(channel->wrapped,
210 (grpc_connectivity_state)last_state,
211 deadline->wrapped, completion_queue,
212 NULL);
213 grpc_event event =
214 grpc_completion_queue_pluck(completion_queue, NULL,
215 gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
Stanley Cheung1567c0c2015-08-13 11:12:54 -0700216 RETURN_BOOL(event.success);
Stanley Cheunga63fdd02015-08-11 15:11:11 -0700217}
218
219/**
mlumishb892a272014-12-09 16:28:23 -0800220 * Close the channel
thinkerou03dc2192016-08-16 19:31:44 +0800221 * @return void
mlumishb892a272014-12-09 16:28:23 -0800222 */
Craig Tillerb5dcec52015-01-13 11:13:42 -0800223PHP_METHOD(Channel, close) {
thinkeroua3730b72016-07-20 16:59:54 +0800224 wrapped_grpc_channel *channel = Z_WRAPPED_GRPC_CHANNEL_P(getThis());
Craig Tillerb5dcec52015-01-13 11:13:42 -0800225 if (channel->wrapped != NULL) {
mlumishb892a272014-12-09 16:28:23 -0800226 grpc_channel_destroy(channel->wrapped);
227 channel->wrapped = NULL;
228 }
229}
230
Stanley Cheung6a5c83d2017-02-16 12:25:32 -0800231ZEND_BEGIN_ARG_INFO_EX(arginfo_construct, 0, 0, 2)
232 ZEND_ARG_INFO(0, target)
233 ZEND_ARG_INFO(0, args)
234ZEND_END_ARG_INFO()
235
236ZEND_BEGIN_ARG_INFO_EX(arginfo_getTarget, 0, 0, 0)
237ZEND_END_ARG_INFO()
238
239ZEND_BEGIN_ARG_INFO_EX(arginfo_getConnectivityState, 0, 0, 0)
240 ZEND_ARG_INFO(0, try_to_connect)
241ZEND_END_ARG_INFO()
242
243ZEND_BEGIN_ARG_INFO_EX(arginfo_watchConnectivityState, 0, 0, 2)
244 ZEND_ARG_INFO(0, last_state)
245 ZEND_ARG_INFO(0, deadline)
246ZEND_END_ARG_INFO()
247
248ZEND_BEGIN_ARG_INFO_EX(arginfo_close, 0, 0, 0)
249ZEND_END_ARG_INFO()
250
mlumishb892a272014-12-09 16:28:23 -0800251static zend_function_entry channel_methods[] = {
Stanley Cheung6a5c83d2017-02-16 12:25:32 -0800252 PHP_ME(Channel, __construct, arginfo_construct,
253 ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
254 PHP_ME(Channel, getTarget, arginfo_getTarget,
255 ZEND_ACC_PUBLIC)
256 PHP_ME(Channel, getConnectivityState, arginfo_getConnectivityState,
257 ZEND_ACC_PUBLIC)
258 PHP_ME(Channel, watchConnectivityState, arginfo_watchConnectivityState,
259 ZEND_ACC_PUBLIC)
260 PHP_ME(Channel, close, arginfo_close,
261 ZEND_ACC_PUBLIC)
thinkeroua3730b72016-07-20 16:59:54 +0800262 PHP_FE_END
263};
mlumishb892a272014-12-09 16:28:23 -0800264
Craig Tillerb5dcec52015-01-13 11:13:42 -0800265void grpc_init_channel(TSRMLS_D) {
mlumishb892a272014-12-09 16:28:23 -0800266 zend_class_entry ce;
267 INIT_CLASS_ENTRY(ce, "Grpc\\Channel", channel_methods);
268 ce.create_object = create_wrapped_grpc_channel;
269 grpc_ce_channel = zend_register_internal_class(&ce TSRMLS_CC);
thinkerou5dafd822016-07-28 22:43:38 +0800270 PHP_GRPC_INIT_HANDLER(wrapped_grpc_channel, channel_ce_handlers);
mlumishb892a272014-12-09 16:28:23 -0800271}