xref: /aosp_15_r20/external/grpc-grpc/src/php/ext/grpc/channel.c (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
1*cc02d7e2SAndroid Build Coastguard Worker /*
2*cc02d7e2SAndroid Build Coastguard Worker  *
3*cc02d7e2SAndroid Build Coastguard Worker  * Copyright 2015 gRPC authors.
4*cc02d7e2SAndroid Build Coastguard Worker  *
5*cc02d7e2SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
6*cc02d7e2SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
7*cc02d7e2SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
8*cc02d7e2SAndroid Build Coastguard Worker  *
9*cc02d7e2SAndroid Build Coastguard Worker  *     http://www.apache.org/licenses/LICENSE-2.0
10*cc02d7e2SAndroid Build Coastguard Worker  *
11*cc02d7e2SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
12*cc02d7e2SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
13*cc02d7e2SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*cc02d7e2SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
15*cc02d7e2SAndroid Build Coastguard Worker  * limitations under the License.
16*cc02d7e2SAndroid Build Coastguard Worker  *
17*cc02d7e2SAndroid Build Coastguard Worker  */
18*cc02d7e2SAndroid Build Coastguard Worker 
19*cc02d7e2SAndroid Build Coastguard Worker /**
20*cc02d7e2SAndroid Build Coastguard Worker  * class Channel
21*cc02d7e2SAndroid Build Coastguard Worker  * @see https://github.com/grpc/grpc/tree/master/src/php/ext/grpc/channel.c
22*cc02d7e2SAndroid Build Coastguard Worker  */
23*cc02d7e2SAndroid Build Coastguard Worker 
24*cc02d7e2SAndroid Build Coastguard Worker #include "channel.h"
25*cc02d7e2SAndroid Build Coastguard Worker 
26*cc02d7e2SAndroid Build Coastguard Worker #include <ext/standard/php_var.h>
27*cc02d7e2SAndroid Build Coastguard Worker #include <ext/standard/sha1.h>
28*cc02d7e2SAndroid Build Coastguard Worker #include <zend_smart_str.h>
29*cc02d7e2SAndroid Build Coastguard Worker #include <ext/spl/spl_exceptions.h>
30*cc02d7e2SAndroid Build Coastguard Worker #include <zend_exceptions.h>
31*cc02d7e2SAndroid Build Coastguard Worker 
32*cc02d7e2SAndroid Build Coastguard Worker #include <grpc/grpc_security.h>
33*cc02d7e2SAndroid Build Coastguard Worker #include <grpc/support/alloc.h>
34*cc02d7e2SAndroid Build Coastguard Worker #include <grpc/support/log.h>
35*cc02d7e2SAndroid Build Coastguard Worker 
36*cc02d7e2SAndroid Build Coastguard Worker #include "completion_queue.h"
37*cc02d7e2SAndroid Build Coastguard Worker #include "channel_credentials.h"
38*cc02d7e2SAndroid Build Coastguard Worker #include "timeval.h"
39*cc02d7e2SAndroid Build Coastguard Worker 
40*cc02d7e2SAndroid Build Coastguard Worker zend_class_entry *grpc_ce_channel;
41*cc02d7e2SAndroid Build Coastguard Worker PHP_GRPC_DECLARE_OBJECT_HANDLER(channel_ce_handlers)
42*cc02d7e2SAndroid Build Coastguard Worker static gpr_mu global_persistent_list_mu;
43*cc02d7e2SAndroid Build Coastguard Worker int le_plink;
44*cc02d7e2SAndroid Build Coastguard Worker int le_bound;
45*cc02d7e2SAndroid Build Coastguard Worker extern HashTable grpc_persistent_list;
46*cc02d7e2SAndroid Build Coastguard Worker extern HashTable grpc_target_upper_bound_map;
47*cc02d7e2SAndroid Build Coastguard Worker 
free_grpc_channel_wrapper(grpc_channel_wrapper * channel,bool free_channel)48*cc02d7e2SAndroid Build Coastguard Worker void free_grpc_channel_wrapper(grpc_channel_wrapper* channel, bool free_channel) {
49*cc02d7e2SAndroid Build Coastguard Worker   if (free_channel && channel->wrapped) {
50*cc02d7e2SAndroid Build Coastguard Worker     grpc_channel_destroy(channel->wrapped);
51*cc02d7e2SAndroid Build Coastguard Worker     channel->wrapped = NULL;
52*cc02d7e2SAndroid Build Coastguard Worker   }
53*cc02d7e2SAndroid Build Coastguard Worker   free(channel->target);
54*cc02d7e2SAndroid Build Coastguard Worker   free(channel->args_hashstr);
55*cc02d7e2SAndroid Build Coastguard Worker   free(channel->creds_hashstr);
56*cc02d7e2SAndroid Build Coastguard Worker   free(channel->key);
57*cc02d7e2SAndroid Build Coastguard Worker   channel->target = NULL;
58*cc02d7e2SAndroid Build Coastguard Worker   channel->args_hashstr = NULL;
59*cc02d7e2SAndroid Build Coastguard Worker   channel->creds_hashstr = NULL;
60*cc02d7e2SAndroid Build Coastguard Worker   channel->key = NULL;
61*cc02d7e2SAndroid Build Coastguard Worker }
62*cc02d7e2SAndroid Build Coastguard Worker 
php_grpc_channel_ref(grpc_channel_wrapper * wrapper)63*cc02d7e2SAndroid Build Coastguard Worker void php_grpc_channel_ref(grpc_channel_wrapper* wrapper) {
64*cc02d7e2SAndroid Build Coastguard Worker   gpr_mu_lock(&wrapper->mu);
65*cc02d7e2SAndroid Build Coastguard Worker   wrapper->ref_count += 1;
66*cc02d7e2SAndroid Build Coastguard Worker   gpr_mu_unlock(&wrapper->mu);
67*cc02d7e2SAndroid Build Coastguard Worker }
68*cc02d7e2SAndroid Build Coastguard Worker 
php_grpc_channel_unref(grpc_channel_wrapper * wrapper)69*cc02d7e2SAndroid Build Coastguard Worker void php_grpc_channel_unref(grpc_channel_wrapper* wrapper) {
70*cc02d7e2SAndroid Build Coastguard Worker   gpr_mu_lock(&wrapper->mu);
71*cc02d7e2SAndroid Build Coastguard Worker   wrapper->ref_count -= 1;
72*cc02d7e2SAndroid Build Coastguard Worker   if (wrapper->ref_count == 0) {
73*cc02d7e2SAndroid Build Coastguard Worker     free_grpc_channel_wrapper(wrapper, true);
74*cc02d7e2SAndroid Build Coastguard Worker     gpr_mu_unlock(&wrapper->mu);
75*cc02d7e2SAndroid Build Coastguard Worker     free(wrapper);
76*cc02d7e2SAndroid Build Coastguard Worker     wrapper = NULL;
77*cc02d7e2SAndroid Build Coastguard Worker     return;
78*cc02d7e2SAndroid Build Coastguard Worker   }
79*cc02d7e2SAndroid Build Coastguard Worker   gpr_mu_unlock(&wrapper->mu);
80*cc02d7e2SAndroid Build Coastguard Worker }
81*cc02d7e2SAndroid Build Coastguard Worker 
82*cc02d7e2SAndroid Build Coastguard Worker /* Frees and destroys an instance of wrapped_grpc_channel */
83*cc02d7e2SAndroid Build Coastguard Worker PHP_GRPC_FREE_WRAPPED_FUNC_START(wrapped_grpc_channel)
84*cc02d7e2SAndroid Build Coastguard Worker   // In_persistent_list is used when the user don't close the channel,
85*cc02d7e2SAndroid Build Coastguard Worker   // In this case, channels not in the list should be freed.
86*cc02d7e2SAndroid Build Coastguard Worker   if (p->wrapper != NULL) {
87*cc02d7e2SAndroid Build Coastguard Worker     php_grpc_channel_unref(p->wrapper);
88*cc02d7e2SAndroid Build Coastguard Worker     p->wrapper = NULL;
89*cc02d7e2SAndroid Build Coastguard Worker   }
PHP_GRPC_FREE_WRAPPED_FUNC_END()90*cc02d7e2SAndroid Build Coastguard Worker PHP_GRPC_FREE_WRAPPED_FUNC_END()
91*cc02d7e2SAndroid Build Coastguard Worker 
92*cc02d7e2SAndroid Build Coastguard Worker /* Initializes an instance of wrapped_grpc_channel to be associated with an
93*cc02d7e2SAndroid Build Coastguard Worker  * object of a class specified by class_type */
94*cc02d7e2SAndroid Build Coastguard Worker php_grpc_zend_object create_wrapped_grpc_channel(zend_class_entry *class_type
95*cc02d7e2SAndroid Build Coastguard Worker                                                  TSRMLS_DC) {
96*cc02d7e2SAndroid Build Coastguard Worker   PHP_GRPC_ALLOC_CLASS_OBJECT(wrapped_grpc_channel);
97*cc02d7e2SAndroid Build Coastguard Worker   zend_object_std_init(&intern->std, class_type TSRMLS_CC);
98*cc02d7e2SAndroid Build Coastguard Worker   object_properties_init(&intern->std, class_type);
99*cc02d7e2SAndroid Build Coastguard Worker   PHP_GRPC_FREE_CLASS_OBJECT(wrapped_grpc_channel, channel_ce_handlers);
100*cc02d7e2SAndroid Build Coastguard Worker }
101*cc02d7e2SAndroid Build Coastguard Worker 
php_grpc_not_channel_arg_key(const char * key)102*cc02d7e2SAndroid Build Coastguard Worker static bool php_grpc_not_channel_arg_key(const char* key) {
103*cc02d7e2SAndroid Build Coastguard Worker   static const char* ignoredKeys[] = {
104*cc02d7e2SAndroid Build Coastguard Worker     "credentials",
105*cc02d7e2SAndroid Build Coastguard Worker     "force_new",
106*cc02d7e2SAndroid Build Coastguard Worker     "grpc_target_persist_bound",
107*cc02d7e2SAndroid Build Coastguard Worker   };
108*cc02d7e2SAndroid Build Coastguard Worker 
109*cc02d7e2SAndroid Build Coastguard Worker   for (int i = 0; i < sizeof(ignoredKeys) / sizeof(ignoredKeys[0]); i++) {
110*cc02d7e2SAndroid Build Coastguard Worker     if (strcmp(key, ignoredKeys[i]) == 0) {
111*cc02d7e2SAndroid Build Coastguard Worker       return true;
112*cc02d7e2SAndroid Build Coastguard Worker     }
113*cc02d7e2SAndroid Build Coastguard Worker   }
114*cc02d7e2SAndroid Build Coastguard Worker   return false;
115*cc02d7e2SAndroid Build Coastguard Worker }
116*cc02d7e2SAndroid Build Coastguard Worker 
php_grpc_read_args_array(zval * args_array,grpc_channel_args * args TSRMLS_DC)117*cc02d7e2SAndroid Build Coastguard Worker int php_grpc_read_args_array(zval *args_array,
118*cc02d7e2SAndroid Build Coastguard Worker                              grpc_channel_args *args TSRMLS_DC) {
119*cc02d7e2SAndroid Build Coastguard Worker   HashTable *array_hash;
120*cc02d7e2SAndroid Build Coastguard Worker   int args_index;
121*cc02d7e2SAndroid Build Coastguard Worker   array_hash = Z_ARRVAL_P(args_array);
122*cc02d7e2SAndroid Build Coastguard Worker   if (!array_hash) {
123*cc02d7e2SAndroid Build Coastguard Worker     zend_throw_exception(spl_ce_InvalidArgumentException,
124*cc02d7e2SAndroid Build Coastguard Worker                          "array_hash is NULL", 1 TSRMLS_CC);
125*cc02d7e2SAndroid Build Coastguard Worker     return FAILURE;
126*cc02d7e2SAndroid Build Coastguard Worker   }
127*cc02d7e2SAndroid Build Coastguard Worker 
128*cc02d7e2SAndroid Build Coastguard Worker   args->args = ecalloc(zend_hash_num_elements(array_hash), sizeof(grpc_arg));
129*cc02d7e2SAndroid Build Coastguard Worker   args_index = 0;
130*cc02d7e2SAndroid Build Coastguard Worker 
131*cc02d7e2SAndroid Build Coastguard Worker   char *key = NULL;
132*cc02d7e2SAndroid Build Coastguard Worker   zval *data;
133*cc02d7e2SAndroid Build Coastguard Worker   int key_type;
134*cc02d7e2SAndroid Build Coastguard Worker 
135*cc02d7e2SAndroid Build Coastguard Worker   PHP_GRPC_HASH_FOREACH_STR_KEY_VAL_START(array_hash, key, key_type, data)
136*cc02d7e2SAndroid Build Coastguard Worker     if (key_type != HASH_KEY_IS_STRING) {
137*cc02d7e2SAndroid Build Coastguard Worker       zend_throw_exception(spl_ce_InvalidArgumentException,
138*cc02d7e2SAndroid Build Coastguard Worker                            "args keys must be strings", 1 TSRMLS_CC);
139*cc02d7e2SAndroid Build Coastguard Worker       return FAILURE;
140*cc02d7e2SAndroid Build Coastguard Worker     }
141*cc02d7e2SAndroid Build Coastguard Worker 
142*cc02d7e2SAndroid Build Coastguard Worker     if (php_grpc_not_channel_arg_key(key)) {
143*cc02d7e2SAndroid Build Coastguard Worker       continue;
144*cc02d7e2SAndroid Build Coastguard Worker     }
145*cc02d7e2SAndroid Build Coastguard Worker 
146*cc02d7e2SAndroid Build Coastguard Worker     args->args[args_index].key = key;
147*cc02d7e2SAndroid Build Coastguard Worker     switch (Z_TYPE_P(data)) {
148*cc02d7e2SAndroid Build Coastguard Worker     case IS_LONG:
149*cc02d7e2SAndroid Build Coastguard Worker       args->args[args_index].value.integer = (int)Z_LVAL_P(data);
150*cc02d7e2SAndroid Build Coastguard Worker       args->args[args_index].type = GRPC_ARG_INTEGER;
151*cc02d7e2SAndroid Build Coastguard Worker       break;
152*cc02d7e2SAndroid Build Coastguard Worker     case IS_STRING:
153*cc02d7e2SAndroid Build Coastguard Worker       args->args[args_index].value.string = Z_STRVAL_P(data);
154*cc02d7e2SAndroid Build Coastguard Worker       args->args[args_index].type = GRPC_ARG_STRING;
155*cc02d7e2SAndroid Build Coastguard Worker       break;
156*cc02d7e2SAndroid Build Coastguard Worker     default:
157*cc02d7e2SAndroid Build Coastguard Worker       zend_throw_exception(spl_ce_InvalidArgumentException,
158*cc02d7e2SAndroid Build Coastguard Worker                            "args values must be int or string", 1 TSRMLS_CC);
159*cc02d7e2SAndroid Build Coastguard Worker       return FAILURE;
160*cc02d7e2SAndroid Build Coastguard Worker     }
161*cc02d7e2SAndroid Build Coastguard Worker     args_index++;
162*cc02d7e2SAndroid Build Coastguard Worker   PHP_GRPC_HASH_FOREACH_END()
163*cc02d7e2SAndroid Build Coastguard Worker   args->num_args = args_index;
164*cc02d7e2SAndroid Build Coastguard Worker   return SUCCESS;
165*cc02d7e2SAndroid Build Coastguard Worker }
166*cc02d7e2SAndroid Build Coastguard Worker 
generate_sha1_str(char * sha1str,char * str,php_grpc_int len)167*cc02d7e2SAndroid Build Coastguard Worker void generate_sha1_str(char *sha1str, char *str, php_grpc_int len) {
168*cc02d7e2SAndroid Build Coastguard Worker   PHP_SHA1_CTX context;
169*cc02d7e2SAndroid Build Coastguard Worker   unsigned char digest[20];
170*cc02d7e2SAndroid Build Coastguard Worker   sha1str[0] = '\0';
171*cc02d7e2SAndroid Build Coastguard Worker   PHP_SHA1Init(&context);
172*cc02d7e2SAndroid Build Coastguard Worker   PHP_GRPC_SHA1Update(&context, str, len);
173*cc02d7e2SAndroid Build Coastguard Worker   PHP_SHA1Final(digest, &context);
174*cc02d7e2SAndroid Build Coastguard Worker   make_sha1_digest(sha1str, digest);
175*cc02d7e2SAndroid Build Coastguard Worker }
176*cc02d7e2SAndroid Build Coastguard Worker 
php_grpc_persistent_list_delete_unused_channel(char * target,target_bound_le_t * target_bound_status TSRMLS_DC)177*cc02d7e2SAndroid Build Coastguard Worker bool php_grpc_persistent_list_delete_unused_channel(
178*cc02d7e2SAndroid Build Coastguard Worker     char* target,
179*cc02d7e2SAndroid Build Coastguard Worker     target_bound_le_t* target_bound_status TSRMLS_DC) {
180*cc02d7e2SAndroid Build Coastguard Worker   zval *data;
181*cc02d7e2SAndroid Build Coastguard Worker   PHP_GRPC_HASH_FOREACH_VAL_START(&grpc_persistent_list, data)
182*cc02d7e2SAndroid Build Coastguard Worker     php_grpc_zend_resource *rsrc  = (php_grpc_zend_resource*) PHP_GRPC_HASH_VALPTR_TO_VAL(data)
183*cc02d7e2SAndroid Build Coastguard Worker     if (rsrc == NULL) {
184*cc02d7e2SAndroid Build Coastguard Worker       break;
185*cc02d7e2SAndroid Build Coastguard Worker     }
186*cc02d7e2SAndroid Build Coastguard Worker     channel_persistent_le_t* le = rsrc->ptr;
187*cc02d7e2SAndroid Build Coastguard Worker     // Find the channel sharing the same target.
188*cc02d7e2SAndroid Build Coastguard Worker     if (strcmp(le->channel->target, target) == 0) {
189*cc02d7e2SAndroid Build Coastguard Worker       // ref_count=1 means that only the map holds the reference to the channel.
190*cc02d7e2SAndroid Build Coastguard Worker       if (le->channel->ref_count == 1) {
191*cc02d7e2SAndroid Build Coastguard Worker         php_grpc_delete_persistent_list_entry(le->channel->key,
192*cc02d7e2SAndroid Build Coastguard Worker                                               strlen(le->channel->key)
193*cc02d7e2SAndroid Build Coastguard Worker                                               TSRMLS_CC);
194*cc02d7e2SAndroid Build Coastguard Worker         target_bound_status->current_count -= 1;
195*cc02d7e2SAndroid Build Coastguard Worker         if (target_bound_status->current_count < target_bound_status->upper_bound) {
196*cc02d7e2SAndroid Build Coastguard Worker           return true;
197*cc02d7e2SAndroid Build Coastguard Worker         }
198*cc02d7e2SAndroid Build Coastguard Worker       }
199*cc02d7e2SAndroid Build Coastguard Worker     }
200*cc02d7e2SAndroid Build Coastguard Worker   PHP_GRPC_HASH_FOREACH_END()
201*cc02d7e2SAndroid Build Coastguard Worker   return false;
202*cc02d7e2SAndroid Build Coastguard Worker }
203*cc02d7e2SAndroid Build Coastguard Worker 
update_and_get_target_upper_bound(char * target,int bound)204*cc02d7e2SAndroid Build Coastguard Worker target_bound_le_t* update_and_get_target_upper_bound(char* target, int bound) {
205*cc02d7e2SAndroid Build Coastguard Worker   php_grpc_zend_resource *rsrc;
206*cc02d7e2SAndroid Build Coastguard Worker   target_bound_le_t* target_bound_status;
207*cc02d7e2SAndroid Build Coastguard Worker   php_grpc_int key_len = strlen(target);
208*cc02d7e2SAndroid Build Coastguard Worker   if (!(PHP_GRPC_PERSISTENT_LIST_FIND(&grpc_target_upper_bound_map, target,
209*cc02d7e2SAndroid Build Coastguard Worker       key_len, rsrc))) {
210*cc02d7e2SAndroid Build Coastguard Worker     // Target is not persisted.
211*cc02d7e2SAndroid Build Coastguard Worker     php_grpc_zend_resource new_rsrc;
212*cc02d7e2SAndroid Build Coastguard Worker     target_bound_status = malloc(sizeof(target_bound_le_t));
213*cc02d7e2SAndroid Build Coastguard Worker     if (bound == -1) {
214*cc02d7e2SAndroid Build Coastguard Worker       // If the bound is not set, use 1 as default.s
215*cc02d7e2SAndroid Build Coastguard Worker       bound = 1;
216*cc02d7e2SAndroid Build Coastguard Worker     }
217*cc02d7e2SAndroid Build Coastguard Worker     target_bound_status->upper_bound = bound;
218*cc02d7e2SAndroid Build Coastguard Worker     // Init current_count with 1. It should be add 1 when the channel is successfully
219*cc02d7e2SAndroid Build Coastguard Worker     // created and minus 1 when it is removed from the persistent list.
220*cc02d7e2SAndroid Build Coastguard Worker     target_bound_status->current_count = 0;
221*cc02d7e2SAndroid Build Coastguard Worker     new_rsrc.type = le_bound;
222*cc02d7e2SAndroid Build Coastguard Worker     new_rsrc.ptr = target_bound_status;
223*cc02d7e2SAndroid Build Coastguard Worker     gpr_mu_lock(&global_persistent_list_mu);
224*cc02d7e2SAndroid Build Coastguard Worker     PHP_GRPC_PERSISTENT_LIST_UPDATE(&grpc_target_upper_bound_map,
225*cc02d7e2SAndroid Build Coastguard Worker                                     target, key_len, (void *)&new_rsrc);
226*cc02d7e2SAndroid Build Coastguard Worker     gpr_mu_unlock(&global_persistent_list_mu);
227*cc02d7e2SAndroid Build Coastguard Worker   } else {
228*cc02d7e2SAndroid Build Coastguard Worker     // The target already in the map recording the upper bound.
229*cc02d7e2SAndroid Build Coastguard Worker     // If no newer bound set, use the original now.
230*cc02d7e2SAndroid Build Coastguard Worker     target_bound_status = (target_bound_le_t *)rsrc->ptr;
231*cc02d7e2SAndroid Build Coastguard Worker     if (bound != -1) {
232*cc02d7e2SAndroid Build Coastguard Worker       target_bound_status->upper_bound = bound;
233*cc02d7e2SAndroid Build Coastguard Worker     }
234*cc02d7e2SAndroid Build Coastguard Worker   }
235*cc02d7e2SAndroid Build Coastguard Worker   return target_bound_status;
236*cc02d7e2SAndroid Build Coastguard Worker }
237*cc02d7e2SAndroid Build Coastguard Worker 
create_channel(wrapped_grpc_channel * channel,char * target,grpc_channel_args args,wrapped_grpc_channel_credentials * creds)238*cc02d7e2SAndroid Build Coastguard Worker void create_channel(
239*cc02d7e2SAndroid Build Coastguard Worker     wrapped_grpc_channel *channel,
240*cc02d7e2SAndroid Build Coastguard Worker     char *target,
241*cc02d7e2SAndroid Build Coastguard Worker     grpc_channel_args args,
242*cc02d7e2SAndroid Build Coastguard Worker     wrapped_grpc_channel_credentials *creds) {
243*cc02d7e2SAndroid Build Coastguard Worker   if (creds == NULL) {
244*cc02d7e2SAndroid Build Coastguard Worker     grpc_channel_credentials* insecure_creds = grpc_insecure_credentials_create();
245*cc02d7e2SAndroid Build Coastguard Worker     channel->wrapper->wrapped = grpc_channel_create(target, insecure_creds, &args);
246*cc02d7e2SAndroid Build Coastguard Worker     grpc_channel_credentials_release(insecure_creds);
247*cc02d7e2SAndroid Build Coastguard Worker   } else {
248*cc02d7e2SAndroid Build Coastguard Worker     channel->wrapper->wrapped =
249*cc02d7e2SAndroid Build Coastguard Worker         grpc_channel_create(target, creds->wrapped, &args);
250*cc02d7e2SAndroid Build Coastguard Worker   }
251*cc02d7e2SAndroid Build Coastguard Worker   // There is an Grpc\Channel object refer to it.
252*cc02d7e2SAndroid Build Coastguard Worker   php_grpc_channel_ref(channel->wrapper);
253*cc02d7e2SAndroid Build Coastguard Worker   efree(args.args);
254*cc02d7e2SAndroid Build Coastguard Worker }
255*cc02d7e2SAndroid Build Coastguard Worker 
create_and_add_channel_to_persistent_list(wrapped_grpc_channel * channel,char * target,grpc_channel_args args,wrapped_grpc_channel_credentials * creds,char * key,php_grpc_int key_len,int target_upper_bound TSRMLS_DC)256*cc02d7e2SAndroid Build Coastguard Worker void create_and_add_channel_to_persistent_list(
257*cc02d7e2SAndroid Build Coastguard Worker     wrapped_grpc_channel *channel,
258*cc02d7e2SAndroid Build Coastguard Worker     char *target,
259*cc02d7e2SAndroid Build Coastguard Worker     grpc_channel_args args,
260*cc02d7e2SAndroid Build Coastguard Worker     wrapped_grpc_channel_credentials *creds,
261*cc02d7e2SAndroid Build Coastguard Worker     char *key,
262*cc02d7e2SAndroid Build Coastguard Worker     php_grpc_int key_len,
263*cc02d7e2SAndroid Build Coastguard Worker     int target_upper_bound TSRMLS_DC) {
264*cc02d7e2SAndroid Build Coastguard Worker   target_bound_le_t* target_bound_status =
265*cc02d7e2SAndroid Build Coastguard Worker     update_and_get_target_upper_bound(target, target_upper_bound);
266*cc02d7e2SAndroid Build Coastguard Worker   // Check the upper bound status before inserting to the persistent map.
267*cc02d7e2SAndroid Build Coastguard Worker   if (target_bound_status->current_count >=
268*cc02d7e2SAndroid Build Coastguard Worker       target_bound_status->upper_bound) {
269*cc02d7e2SAndroid Build Coastguard Worker     if (!php_grpc_persistent_list_delete_unused_channel(
270*cc02d7e2SAndroid Build Coastguard Worker           target, target_bound_status TSRMLS_CC)) {
271*cc02d7e2SAndroid Build Coastguard Worker       // If no channel can be deleted from the persistent map,
272*cc02d7e2SAndroid Build Coastguard Worker       // do not persist this one.
273*cc02d7e2SAndroid Build Coastguard Worker       create_channel(channel, target, args, creds);
274*cc02d7e2SAndroid Build Coastguard Worker       gpr_log(GPR_INFO, "[Warning] The number of channel for the"
275*cc02d7e2SAndroid Build Coastguard Worker                  " target %s is maxed out bounded.\n", target);
276*cc02d7e2SAndroid Build Coastguard Worker       gpr_log(GPR_INFO, "[Warning] Target upper bound: %d. Current size: %d.\n",
277*cc02d7e2SAndroid Build Coastguard Worker                  target_bound_status->upper_bound,
278*cc02d7e2SAndroid Build Coastguard Worker                  target_bound_status->current_count);
279*cc02d7e2SAndroid Build Coastguard Worker       gpr_log(GPR_INFO, "[Warning] Target %s will not be persisted.\n", target);
280*cc02d7e2SAndroid Build Coastguard Worker       return;
281*cc02d7e2SAndroid Build Coastguard Worker     }
282*cc02d7e2SAndroid Build Coastguard Worker   }
283*cc02d7e2SAndroid Build Coastguard Worker   // There is space in the persistent map.
284*cc02d7e2SAndroid Build Coastguard Worker   php_grpc_zend_resource new_rsrc;
285*cc02d7e2SAndroid Build Coastguard Worker   channel_persistent_le_t *le;
286*cc02d7e2SAndroid Build Coastguard Worker   // this links each persistent list entry to a destructor
287*cc02d7e2SAndroid Build Coastguard Worker   new_rsrc.type = le_plink;
288*cc02d7e2SAndroid Build Coastguard Worker   le = malloc(sizeof(channel_persistent_le_t));
289*cc02d7e2SAndroid Build Coastguard Worker 
290*cc02d7e2SAndroid Build Coastguard Worker   create_channel(channel, target, args, creds);
291*cc02d7e2SAndroid Build Coastguard Worker   target_bound_status->current_count += 1;
292*cc02d7e2SAndroid Build Coastguard Worker 
293*cc02d7e2SAndroid Build Coastguard Worker   le->channel = channel->wrapper;
294*cc02d7e2SAndroid Build Coastguard Worker   new_rsrc.ptr = le;
295*cc02d7e2SAndroid Build Coastguard Worker   gpr_mu_lock(&global_persistent_list_mu);
296*cc02d7e2SAndroid Build Coastguard Worker   PHP_GRPC_PERSISTENT_LIST_UPDATE(&grpc_persistent_list, key, key_len,
297*cc02d7e2SAndroid Build Coastguard Worker                                   (void *)&new_rsrc);
298*cc02d7e2SAndroid Build Coastguard Worker   // Persistent map refer to it.
299*cc02d7e2SAndroid Build Coastguard Worker   php_grpc_channel_ref(channel->wrapper);
300*cc02d7e2SAndroid Build Coastguard Worker   gpr_mu_unlock(&global_persistent_list_mu);
301*cc02d7e2SAndroid Build Coastguard Worker }
302*cc02d7e2SAndroid Build Coastguard Worker 
303*cc02d7e2SAndroid Build Coastguard Worker /**
304*cc02d7e2SAndroid Build Coastguard Worker  * Construct an instance of the Channel class.
305*cc02d7e2SAndroid Build Coastguard Worker  *
306*cc02d7e2SAndroid Build Coastguard Worker  * By default, the underlying grpc_channel is "persistent". That is, given
307*cc02d7e2SAndroid Build Coastguard Worker  * the same set of parameters passed to the constructor, the same underlying
308*cc02d7e2SAndroid Build Coastguard Worker  * grpc_channel will be returned.
309*cc02d7e2SAndroid Build Coastguard Worker  *
310*cc02d7e2SAndroid Build Coastguard Worker  * If the $args array contains a "credentials" key mapping to a
311*cc02d7e2SAndroid Build Coastguard Worker  * ChannelCredentials object, a secure channel will be created with those
312*cc02d7e2SAndroid Build Coastguard Worker  * credentials.
313*cc02d7e2SAndroid Build Coastguard Worker  *
314*cc02d7e2SAndroid Build Coastguard Worker  * If the $args array contains a "force_new" key mapping to a boolean value
315*cc02d7e2SAndroid Build Coastguard Worker  * of "true", a new and separate underlying grpc_channel will be created
316*cc02d7e2SAndroid Build Coastguard Worker  * and returned. This will not affect existing channels.
317*cc02d7e2SAndroid Build Coastguard Worker  *
318*cc02d7e2SAndroid Build Coastguard Worker  * @param string $target The hostname to associate with this channel
319*cc02d7e2SAndroid Build Coastguard Worker  * @param array $args_array The arguments to pass to the Channel
320*cc02d7e2SAndroid Build Coastguard Worker  */
PHP_METHOD(Channel,__construct)321*cc02d7e2SAndroid Build Coastguard Worker PHP_METHOD(Channel, __construct) {
322*cc02d7e2SAndroid Build Coastguard Worker   wrapped_grpc_channel *channel =
323*cc02d7e2SAndroid Build Coastguard Worker     PHP_GRPC_GET_WRAPPED_OBJECT(wrapped_grpc_channel, getThis());
324*cc02d7e2SAndroid Build Coastguard Worker   zval *creds_obj = NULL;
325*cc02d7e2SAndroid Build Coastguard Worker   char *target;
326*cc02d7e2SAndroid Build Coastguard Worker   php_grpc_int target_length;
327*cc02d7e2SAndroid Build Coastguard Worker   zval *args_array = NULL;
328*cc02d7e2SAndroid Build Coastguard Worker   grpc_channel_args args;
329*cc02d7e2SAndroid Build Coastguard Worker   HashTable *array_hash;
330*cc02d7e2SAndroid Build Coastguard Worker   wrapped_grpc_channel_credentials *creds = NULL;
331*cc02d7e2SAndroid Build Coastguard Worker   php_grpc_zend_resource *rsrc;
332*cc02d7e2SAndroid Build Coastguard Worker   bool force_new = false;
333*cc02d7e2SAndroid Build Coastguard Worker   zval *force_new_obj = NULL;
334*cc02d7e2SAndroid Build Coastguard Worker   int target_upper_bound = -1;
335*cc02d7e2SAndroid Build Coastguard Worker 
336*cc02d7e2SAndroid Build Coastguard Worker   /* "sa" == 1 string, 1 array */
337*cc02d7e2SAndroid Build Coastguard Worker   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa", &target,
338*cc02d7e2SAndroid Build Coastguard Worker                             &target_length, &args_array) == FAILURE) {
339*cc02d7e2SAndroid Build Coastguard Worker     zend_throw_exception(spl_ce_InvalidArgumentException,
340*cc02d7e2SAndroid Build Coastguard Worker                          "Channel expects a string and an array", 1 TSRMLS_CC);
341*cc02d7e2SAndroid Build Coastguard Worker     return;
342*cc02d7e2SAndroid Build Coastguard Worker   }
343*cc02d7e2SAndroid Build Coastguard Worker   array_hash = Z_ARRVAL_P(args_array);
344*cc02d7e2SAndroid Build Coastguard Worker   if (php_grpc_zend_hash_find(array_hash, "credentials", sizeof("credentials"),
345*cc02d7e2SAndroid Build Coastguard Worker                               (void **)&creds_obj) == SUCCESS) {
346*cc02d7e2SAndroid Build Coastguard Worker     if (Z_TYPE_P(creds_obj) == IS_NULL) {
347*cc02d7e2SAndroid Build Coastguard Worker       creds = NULL;
348*cc02d7e2SAndroid Build Coastguard Worker     } else if (PHP_GRPC_GET_CLASS_ENTRY(creds_obj) !=
349*cc02d7e2SAndroid Build Coastguard Worker                grpc_ce_channel_credentials) {
350*cc02d7e2SAndroid Build Coastguard Worker       zend_throw_exception(spl_ce_InvalidArgumentException,
351*cc02d7e2SAndroid Build Coastguard Worker                            "credentials must be a ChannelCredentials object",
352*cc02d7e2SAndroid Build Coastguard Worker                            1 TSRMLS_CC);
353*cc02d7e2SAndroid Build Coastguard Worker       return;
354*cc02d7e2SAndroid Build Coastguard Worker     } else {
355*cc02d7e2SAndroid Build Coastguard Worker       creds = PHP_GRPC_GET_WRAPPED_OBJECT(wrapped_grpc_channel_credentials,
356*cc02d7e2SAndroid Build Coastguard Worker                                           creds_obj);
357*cc02d7e2SAndroid Build Coastguard Worker     }
358*cc02d7e2SAndroid Build Coastguard Worker   }
359*cc02d7e2SAndroid Build Coastguard Worker   if (php_grpc_zend_hash_find(array_hash, "force_new", sizeof("force_new"),
360*cc02d7e2SAndroid Build Coastguard Worker                               (void **)&force_new_obj) == SUCCESS) {
361*cc02d7e2SAndroid Build Coastguard Worker     if (PHP_GRPC_BVAL_IS_TRUE(force_new_obj)) {
362*cc02d7e2SAndroid Build Coastguard Worker       force_new = true;
363*cc02d7e2SAndroid Build Coastguard Worker     }
364*cc02d7e2SAndroid Build Coastguard Worker   }
365*cc02d7e2SAndroid Build Coastguard Worker 
366*cc02d7e2SAndroid Build Coastguard Worker   if (php_grpc_zend_hash_find(array_hash, "grpc_target_persist_bound",
367*cc02d7e2SAndroid Build Coastguard Worker                               sizeof("grpc_target_persist_bound"),
368*cc02d7e2SAndroid Build Coastguard Worker                               (void **)&force_new_obj) == SUCCESS) {
369*cc02d7e2SAndroid Build Coastguard Worker     if (Z_TYPE_P(force_new_obj) != IS_LONG) {
370*cc02d7e2SAndroid Build Coastguard Worker       zend_throw_exception(spl_ce_InvalidArgumentException,
371*cc02d7e2SAndroid Build Coastguard Worker                            "plist_bound must be a number",
372*cc02d7e2SAndroid Build Coastguard Worker                            1 TSRMLS_CC);
373*cc02d7e2SAndroid Build Coastguard Worker     }
374*cc02d7e2SAndroid Build Coastguard Worker     target_upper_bound = (int)Z_LVAL_P(force_new_obj);
375*cc02d7e2SAndroid Build Coastguard Worker   }
376*cc02d7e2SAndroid Build Coastguard Worker 
377*cc02d7e2SAndroid Build Coastguard Worker   // parse the rest of the channel args array
378*cc02d7e2SAndroid Build Coastguard Worker   if (php_grpc_read_args_array(args_array, &args TSRMLS_CC) == FAILURE) {
379*cc02d7e2SAndroid Build Coastguard Worker     efree(args.args);
380*cc02d7e2SAndroid Build Coastguard Worker     return;
381*cc02d7e2SAndroid Build Coastguard Worker   }
382*cc02d7e2SAndroid Build Coastguard Worker 
383*cc02d7e2SAndroid Build Coastguard Worker   // Construct a hashkey for the persistent channel
384*cc02d7e2SAndroid Build Coastguard Worker   // Currently, the hashkey contains 3 parts:
385*cc02d7e2SAndroid Build Coastguard Worker   // 1. hostname
386*cc02d7e2SAndroid Build Coastguard Worker   // 2. hash value of the channel args (args_array excluding "credentials",
387*cc02d7e2SAndroid Build Coastguard Worker   //    "force_new" and "grpc_target_persist_bound")
388*cc02d7e2SAndroid Build Coastguard Worker   // 3. (optional) hash value of the ChannelCredentials object
389*cc02d7e2SAndroid Build Coastguard Worker 
390*cc02d7e2SAndroid Build Coastguard Worker   char sha1str[41] = { 0 };
391*cc02d7e2SAndroid Build Coastguard Worker   unsigned char digest[20] = { 0 };
392*cc02d7e2SAndroid Build Coastguard Worker   PHP_SHA1_CTX context;
393*cc02d7e2SAndroid Build Coastguard Worker   PHP_SHA1Init(&context);
394*cc02d7e2SAndroid Build Coastguard Worker   for (int i = 0; i < args.num_args; i++) {
395*cc02d7e2SAndroid Build Coastguard Worker     PHP_GRPC_SHA1Update(&context, args.args[i].key, strlen(args.args[i].key) + 1);
396*cc02d7e2SAndroid Build Coastguard Worker     switch (args.args[i].type) {
397*cc02d7e2SAndroid Build Coastguard Worker     case GRPC_ARG_INTEGER:
398*cc02d7e2SAndroid Build Coastguard Worker       PHP_GRPC_SHA1Update(&context, &args.args[i].value.integer, 4);
399*cc02d7e2SAndroid Build Coastguard Worker       break;
400*cc02d7e2SAndroid Build Coastguard Worker     case GRPC_ARG_STRING:
401*cc02d7e2SAndroid Build Coastguard Worker       PHP_GRPC_SHA1Update(&context, args.args[i].value.string, strlen(args.args[i].value.string) + 1);
402*cc02d7e2SAndroid Build Coastguard Worker       break;
403*cc02d7e2SAndroid Build Coastguard Worker     default:
404*cc02d7e2SAndroid Build Coastguard Worker       zend_throw_exception(spl_ce_InvalidArgumentException,
405*cc02d7e2SAndroid Build Coastguard Worker                            "args values must be int or string", 1 TSRMLS_CC);
406*cc02d7e2SAndroid Build Coastguard Worker       return;
407*cc02d7e2SAndroid Build Coastguard Worker     }
408*cc02d7e2SAndroid Build Coastguard Worker   };
409*cc02d7e2SAndroid Build Coastguard Worker   PHP_SHA1Final(digest, &context);
410*cc02d7e2SAndroid Build Coastguard Worker   make_sha1_digest(sha1str, digest);
411*cc02d7e2SAndroid Build Coastguard Worker 
412*cc02d7e2SAndroid Build Coastguard Worker   php_grpc_int key_len = target_length + strlen(sha1str);
413*cc02d7e2SAndroid Build Coastguard Worker   if (creds != NULL && creds->hashstr != NULL) {
414*cc02d7e2SAndroid Build Coastguard Worker     key_len += strlen(creds->hashstr);
415*cc02d7e2SAndroid Build Coastguard Worker   }
416*cc02d7e2SAndroid Build Coastguard Worker   char *key = malloc(key_len + 1);
417*cc02d7e2SAndroid Build Coastguard Worker   strcpy(key, target);
418*cc02d7e2SAndroid Build Coastguard Worker   strcat(key, sha1str);
419*cc02d7e2SAndroid Build Coastguard Worker   if (creds != NULL && creds->hashstr != NULL) {
420*cc02d7e2SAndroid Build Coastguard Worker     strcat(key, creds->hashstr);
421*cc02d7e2SAndroid Build Coastguard Worker   }
422*cc02d7e2SAndroid Build Coastguard Worker   channel->wrapper = malloc(sizeof(grpc_channel_wrapper));
423*cc02d7e2SAndroid Build Coastguard Worker   channel->wrapper->ref_count = 0;
424*cc02d7e2SAndroid Build Coastguard Worker   channel->wrapper->key = key;
425*cc02d7e2SAndroid Build Coastguard Worker   channel->wrapper->target = strdup(target);
426*cc02d7e2SAndroid Build Coastguard Worker   channel->wrapper->args_hashstr = strdup(sha1str);
427*cc02d7e2SAndroid Build Coastguard Worker   channel->wrapper->creds_hashstr = NULL;
428*cc02d7e2SAndroid Build Coastguard Worker   channel->wrapper->creds = creds;
429*cc02d7e2SAndroid Build Coastguard Worker   channel->wrapper->args = args;
430*cc02d7e2SAndroid Build Coastguard Worker   if (creds != NULL && creds->hashstr != NULL) {
431*cc02d7e2SAndroid Build Coastguard Worker     php_grpc_int creds_hashstr_len = strlen(creds->hashstr);
432*cc02d7e2SAndroid Build Coastguard Worker     char *channel_creds_hashstr = malloc(creds_hashstr_len + 1);
433*cc02d7e2SAndroid Build Coastguard Worker     strcpy(channel_creds_hashstr, creds->hashstr);
434*cc02d7e2SAndroid Build Coastguard Worker     channel->wrapper->creds_hashstr = channel_creds_hashstr;
435*cc02d7e2SAndroid Build Coastguard Worker   }
436*cc02d7e2SAndroid Build Coastguard Worker 
437*cc02d7e2SAndroid Build Coastguard Worker   gpr_mu_init(&channel->wrapper->mu);
438*cc02d7e2SAndroid Build Coastguard Worker   if (force_new || (creds != NULL && creds->has_call_creds)) {
439*cc02d7e2SAndroid Build Coastguard Worker     // If the ChannelCredentials object was composed with a CallCredentials
440*cc02d7e2SAndroid Build Coastguard Worker     // object, there is no way we can tell them apart. Do NOT persist
441*cc02d7e2SAndroid Build Coastguard Worker     // them. They should be individually destroyed.
442*cc02d7e2SAndroid Build Coastguard Worker     create_channel(channel, target, args, creds);
443*cc02d7e2SAndroid Build Coastguard Worker   } else if (!(PHP_GRPC_PERSISTENT_LIST_FIND(&grpc_persistent_list, key,
444*cc02d7e2SAndroid Build Coastguard Worker                                              key_len, rsrc))) {
445*cc02d7e2SAndroid Build Coastguard Worker     create_and_add_channel_to_persistent_list(
446*cc02d7e2SAndroid Build Coastguard Worker         channel, target, args, creds, key, key_len, target_upper_bound TSRMLS_CC);
447*cc02d7e2SAndroid Build Coastguard Worker   } else {
448*cc02d7e2SAndroid Build Coastguard Worker     // Found a previously stored channel in the persistent list
449*cc02d7e2SAndroid Build Coastguard Worker     channel_persistent_le_t *le = (channel_persistent_le_t *)rsrc->ptr;
450*cc02d7e2SAndroid Build Coastguard Worker     if (strcmp(target, le->channel->target) != 0 ||
451*cc02d7e2SAndroid Build Coastguard Worker         strcmp(sha1str, le->channel->args_hashstr) != 0 ||
452*cc02d7e2SAndroid Build Coastguard Worker         (creds != NULL && creds->hashstr != NULL &&
453*cc02d7e2SAndroid Build Coastguard Worker          strcmp(creds->hashstr, le->channel->creds_hashstr) != 0)) {
454*cc02d7e2SAndroid Build Coastguard Worker       // somehow hash collision
455*cc02d7e2SAndroid Build Coastguard Worker       create_and_add_channel_to_persistent_list(
456*cc02d7e2SAndroid Build Coastguard Worker           channel, target, args, creds, key, key_len, target_upper_bound TSRMLS_CC);
457*cc02d7e2SAndroid Build Coastguard Worker     } else {
458*cc02d7e2SAndroid Build Coastguard Worker       efree(args.args);
459*cc02d7e2SAndroid Build Coastguard Worker       free_grpc_channel_wrapper(channel->wrapper, false);
460*cc02d7e2SAndroid Build Coastguard Worker       gpr_mu_destroy(&channel->wrapper->mu);
461*cc02d7e2SAndroid Build Coastguard Worker       free(channel->wrapper);
462*cc02d7e2SAndroid Build Coastguard Worker       channel->wrapper = NULL;
463*cc02d7e2SAndroid Build Coastguard Worker       channel->wrapper = le->channel;
464*cc02d7e2SAndroid Build Coastguard Worker       // One more Grpc\Channel object refer to it.
465*cc02d7e2SAndroid Build Coastguard Worker       php_grpc_channel_ref(channel->wrapper);
466*cc02d7e2SAndroid Build Coastguard Worker       update_and_get_target_upper_bound(target, target_upper_bound);
467*cc02d7e2SAndroid Build Coastguard Worker     }
468*cc02d7e2SAndroid Build Coastguard Worker   }
469*cc02d7e2SAndroid Build Coastguard Worker }
470*cc02d7e2SAndroid Build Coastguard Worker 
471*cc02d7e2SAndroid Build Coastguard Worker /**
472*cc02d7e2SAndroid Build Coastguard Worker  * Get the endpoint this call/stream is connected to
473*cc02d7e2SAndroid Build Coastguard Worker  * @return string The URI of the endpoint
474*cc02d7e2SAndroid Build Coastguard Worker  */
PHP_METHOD(Channel,getTarget)475*cc02d7e2SAndroid Build Coastguard Worker PHP_METHOD(Channel, getTarget) {
476*cc02d7e2SAndroid Build Coastguard Worker   wrapped_grpc_channel *channel =
477*cc02d7e2SAndroid Build Coastguard Worker     PHP_GRPC_GET_WRAPPED_OBJECT(wrapped_grpc_channel, getThis());
478*cc02d7e2SAndroid Build Coastguard Worker   if (channel->wrapper == NULL) {
479*cc02d7e2SAndroid Build Coastguard Worker     zend_throw_exception(spl_ce_RuntimeException,
480*cc02d7e2SAndroid Build Coastguard Worker                          "getTarget error."
481*cc02d7e2SAndroid Build Coastguard Worker                          "Channel is already closed.", 1 TSRMLS_CC);
482*cc02d7e2SAndroid Build Coastguard Worker     return;
483*cc02d7e2SAndroid Build Coastguard Worker   }
484*cc02d7e2SAndroid Build Coastguard Worker   gpr_mu_lock(&channel->wrapper->mu);
485*cc02d7e2SAndroid Build Coastguard Worker   char *target = grpc_channel_get_target(channel->wrapper->wrapped);
486*cc02d7e2SAndroid Build Coastguard Worker   gpr_mu_unlock(&channel->wrapper->mu);
487*cc02d7e2SAndroid Build Coastguard Worker   PHP_GRPC_RETVAL_STRING(target, 1);
488*cc02d7e2SAndroid Build Coastguard Worker   gpr_free(target);
489*cc02d7e2SAndroid Build Coastguard Worker }
490*cc02d7e2SAndroid Build Coastguard Worker 
491*cc02d7e2SAndroid Build Coastguard Worker /**
492*cc02d7e2SAndroid Build Coastguard Worker  * Get the connectivity state of the channel
493*cc02d7e2SAndroid Build Coastguard Worker  * @param bool $try_to_connect Try to connect on the channel (optional)
494*cc02d7e2SAndroid Build Coastguard Worker  * @return long The grpc connectivity state
495*cc02d7e2SAndroid Build Coastguard Worker  */
PHP_METHOD(Channel,getConnectivityState)496*cc02d7e2SAndroid Build Coastguard Worker PHP_METHOD(Channel, getConnectivityState) {
497*cc02d7e2SAndroid Build Coastguard Worker   wrapped_grpc_channel *channel =
498*cc02d7e2SAndroid Build Coastguard Worker     PHP_GRPC_GET_WRAPPED_OBJECT(wrapped_grpc_channel, getThis());
499*cc02d7e2SAndroid Build Coastguard Worker   if (channel->wrapper == NULL) {
500*cc02d7e2SAndroid Build Coastguard Worker     zend_throw_exception(spl_ce_RuntimeException,
501*cc02d7e2SAndroid Build Coastguard Worker                          "getConnectivityState error."
502*cc02d7e2SAndroid Build Coastguard Worker                          "Channel is already closed.", 1 TSRMLS_CC);
503*cc02d7e2SAndroid Build Coastguard Worker     return;
504*cc02d7e2SAndroid Build Coastguard Worker   }
505*cc02d7e2SAndroid Build Coastguard Worker   gpr_mu_lock(&channel->wrapper->mu);
506*cc02d7e2SAndroid Build Coastguard Worker   bool try_to_connect = false;
507*cc02d7e2SAndroid Build Coastguard Worker   /* "|b" == 1 optional bool */
508*cc02d7e2SAndroid Build Coastguard Worker   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &try_to_connect)
509*cc02d7e2SAndroid Build Coastguard Worker       == FAILURE) {
510*cc02d7e2SAndroid Build Coastguard Worker     zend_throw_exception(spl_ce_InvalidArgumentException,
511*cc02d7e2SAndroid Build Coastguard Worker                          "getConnectivityState expects a bool", 1 TSRMLS_CC);
512*cc02d7e2SAndroid Build Coastguard Worker     gpr_mu_unlock(&channel->wrapper->mu);
513*cc02d7e2SAndroid Build Coastguard Worker     return;
514*cc02d7e2SAndroid Build Coastguard Worker   }
515*cc02d7e2SAndroid Build Coastguard Worker   int state = grpc_channel_check_connectivity_state(channel->wrapper->wrapped,
516*cc02d7e2SAndroid Build Coastguard Worker                                                     (int)try_to_connect);
517*cc02d7e2SAndroid Build Coastguard Worker   gpr_mu_unlock(&channel->wrapper->mu);
518*cc02d7e2SAndroid Build Coastguard Worker   RETURN_LONG(state);
519*cc02d7e2SAndroid Build Coastguard Worker }
520*cc02d7e2SAndroid Build Coastguard Worker 
521*cc02d7e2SAndroid Build Coastguard Worker /**
522*cc02d7e2SAndroid Build Coastguard Worker  * Watch the connectivity state of the channel until it changed
523*cc02d7e2SAndroid Build Coastguard Worker  * @param long $last_state The previous connectivity state of the channel
524*cc02d7e2SAndroid Build Coastguard Worker  * @param Timeval $deadline_obj The deadline this function should wait until
525*cc02d7e2SAndroid Build Coastguard Worker  * @return bool If the connectivity state changes from last_state
526*cc02d7e2SAndroid Build Coastguard Worker  *              before deadline
527*cc02d7e2SAndroid Build Coastguard Worker  */
PHP_METHOD(Channel,watchConnectivityState)528*cc02d7e2SAndroid Build Coastguard Worker PHP_METHOD(Channel, watchConnectivityState) {
529*cc02d7e2SAndroid Build Coastguard Worker   wrapped_grpc_channel *channel =
530*cc02d7e2SAndroid Build Coastguard Worker     PHP_GRPC_GET_WRAPPED_OBJECT(wrapped_grpc_channel, getThis());
531*cc02d7e2SAndroid Build Coastguard Worker   if (channel->wrapper == NULL) {
532*cc02d7e2SAndroid Build Coastguard Worker     zend_throw_exception(spl_ce_RuntimeException,
533*cc02d7e2SAndroid Build Coastguard Worker                          "watchConnectivityState error"
534*cc02d7e2SAndroid Build Coastguard Worker                          "Channel is already closed.", 1 TSRMLS_CC);
535*cc02d7e2SAndroid Build Coastguard Worker     return;
536*cc02d7e2SAndroid Build Coastguard Worker   }
537*cc02d7e2SAndroid Build Coastguard Worker   gpr_mu_lock(&channel->wrapper->mu);
538*cc02d7e2SAndroid Build Coastguard Worker   php_grpc_long last_state;
539*cc02d7e2SAndroid Build Coastguard Worker   zval *deadline_obj;
540*cc02d7e2SAndroid Build Coastguard Worker 
541*cc02d7e2SAndroid Build Coastguard Worker   /* "lO" == 1 long 1 object */
542*cc02d7e2SAndroid Build Coastguard Worker   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lO",
543*cc02d7e2SAndroid Build Coastguard Worker                             &last_state, &deadline_obj,
544*cc02d7e2SAndroid Build Coastguard Worker                             grpc_ce_timeval) == FAILURE) {
545*cc02d7e2SAndroid Build Coastguard Worker     zend_throw_exception(spl_ce_InvalidArgumentException,
546*cc02d7e2SAndroid Build Coastguard Worker                          "watchConnectivityState expects 1 long 1 timeval",
547*cc02d7e2SAndroid Build Coastguard Worker                          1 TSRMLS_CC);
548*cc02d7e2SAndroid Build Coastguard Worker     gpr_mu_unlock(&channel->wrapper->mu);
549*cc02d7e2SAndroid Build Coastguard Worker     return;
550*cc02d7e2SAndroid Build Coastguard Worker   }
551*cc02d7e2SAndroid Build Coastguard Worker 
552*cc02d7e2SAndroid Build Coastguard Worker   wrapped_grpc_timeval *deadline =
553*cc02d7e2SAndroid Build Coastguard Worker     PHP_GRPC_GET_WRAPPED_OBJECT(wrapped_grpc_timeval, deadline_obj);
554*cc02d7e2SAndroid Build Coastguard Worker   grpc_channel_watch_connectivity_state(channel->wrapper->wrapped,
555*cc02d7e2SAndroid Build Coastguard Worker                                         (grpc_connectivity_state)last_state,
556*cc02d7e2SAndroid Build Coastguard Worker                                         deadline->wrapped, completion_queue,
557*cc02d7e2SAndroid Build Coastguard Worker                                         NULL);
558*cc02d7e2SAndroid Build Coastguard Worker   grpc_event event =
559*cc02d7e2SAndroid Build Coastguard Worker       grpc_completion_queue_pluck(completion_queue, NULL,
560*cc02d7e2SAndroid Build Coastguard Worker                                   gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
561*cc02d7e2SAndroid Build Coastguard Worker   gpr_mu_unlock(&channel->wrapper->mu);
562*cc02d7e2SAndroid Build Coastguard Worker   RETURN_BOOL(event.success);
563*cc02d7e2SAndroid Build Coastguard Worker }
564*cc02d7e2SAndroid Build Coastguard Worker 
565*cc02d7e2SAndroid Build Coastguard Worker /**
566*cc02d7e2SAndroid Build Coastguard Worker  * Close the channel
567*cc02d7e2SAndroid Build Coastguard Worker  * @return void
568*cc02d7e2SAndroid Build Coastguard Worker  */
PHP_METHOD(Channel,close)569*cc02d7e2SAndroid Build Coastguard Worker PHP_METHOD(Channel, close) {
570*cc02d7e2SAndroid Build Coastguard Worker   wrapped_grpc_channel *channel =
571*cc02d7e2SAndroid Build Coastguard Worker     PHP_GRPC_GET_WRAPPED_OBJECT(wrapped_grpc_channel, getThis());
572*cc02d7e2SAndroid Build Coastguard Worker   if (channel->wrapper != NULL) {
573*cc02d7e2SAndroid Build Coastguard Worker     php_grpc_channel_unref(channel->wrapper);
574*cc02d7e2SAndroid Build Coastguard Worker     channel->wrapper = NULL;
575*cc02d7e2SAndroid Build Coastguard Worker   }
576*cc02d7e2SAndroid Build Coastguard Worker }
577*cc02d7e2SAndroid Build Coastguard Worker 
578*cc02d7e2SAndroid Build Coastguard Worker // Delete an entry from the persistent list
579*cc02d7e2SAndroid Build Coastguard Worker // Note: this does not destroy or close the underlying grpc_channel
php_grpc_delete_persistent_list_entry(char * key,php_grpc_int key_len TSRMLS_DC)580*cc02d7e2SAndroid Build Coastguard Worker void php_grpc_delete_persistent_list_entry(char *key, php_grpc_int key_len
581*cc02d7e2SAndroid Build Coastguard Worker                                            TSRMLS_DC) {
582*cc02d7e2SAndroid Build Coastguard Worker   php_grpc_zend_resource *rsrc;
583*cc02d7e2SAndroid Build Coastguard Worker   gpr_mu_lock(&global_persistent_list_mu);
584*cc02d7e2SAndroid Build Coastguard Worker   if (PHP_GRPC_PERSISTENT_LIST_FIND(&grpc_persistent_list, key,
585*cc02d7e2SAndroid Build Coastguard Worker                                     key_len, rsrc)) {
586*cc02d7e2SAndroid Build Coastguard Worker     php_grpc_zend_hash_del(&grpc_persistent_list, key, key_len+1);
587*cc02d7e2SAndroid Build Coastguard Worker   }
588*cc02d7e2SAndroid Build Coastguard Worker   gpr_mu_unlock(&global_persistent_list_mu);
589*cc02d7e2SAndroid Build Coastguard Worker }
590*cc02d7e2SAndroid Build Coastguard Worker 
591*cc02d7e2SAndroid Build Coastguard Worker // A destructor associated with each list entry from the persistent list
php_grpc_channel_plink_dtor(php_grpc_zend_resource * rsrc TSRMLS_DC)592*cc02d7e2SAndroid Build Coastguard Worker static void php_grpc_channel_plink_dtor(php_grpc_zend_resource *rsrc
593*cc02d7e2SAndroid Build Coastguard Worker                                         TSRMLS_DC) {
594*cc02d7e2SAndroid Build Coastguard Worker   channel_persistent_le_t *le = (channel_persistent_le_t *)rsrc->ptr;
595*cc02d7e2SAndroid Build Coastguard Worker   if (le == NULL) {
596*cc02d7e2SAndroid Build Coastguard Worker     return;
597*cc02d7e2SAndroid Build Coastguard Worker   }
598*cc02d7e2SAndroid Build Coastguard Worker   if (le->channel != NULL) {
599*cc02d7e2SAndroid Build Coastguard Worker     php_grpc_channel_unref(le->channel);
600*cc02d7e2SAndroid Build Coastguard Worker     le->channel = NULL;
601*cc02d7e2SAndroid Build Coastguard Worker   }
602*cc02d7e2SAndroid Build Coastguard Worker   free(le);
603*cc02d7e2SAndroid Build Coastguard Worker   le = NULL;
604*cc02d7e2SAndroid Build Coastguard Worker }
605*cc02d7e2SAndroid Build Coastguard Worker 
606*cc02d7e2SAndroid Build Coastguard Worker // A destructor associated with each list entry from the target_bound map
php_grpc_target_bound_dtor(php_grpc_zend_resource * rsrc TSRMLS_DC)607*cc02d7e2SAndroid Build Coastguard Worker static void php_grpc_target_bound_dtor(php_grpc_zend_resource *rsrc
608*cc02d7e2SAndroid Build Coastguard Worker                                         TSRMLS_DC) {
609*cc02d7e2SAndroid Build Coastguard Worker   target_bound_le_t *le = (target_bound_le_t *) rsrc->ptr;
610*cc02d7e2SAndroid Build Coastguard Worker   if (le == NULL) {
611*cc02d7e2SAndroid Build Coastguard Worker     return;
612*cc02d7e2SAndroid Build Coastguard Worker   }
613*cc02d7e2SAndroid Build Coastguard Worker   free(le);
614*cc02d7e2SAndroid Build Coastguard Worker   le = NULL;
615*cc02d7e2SAndroid Build Coastguard Worker }
616*cc02d7e2SAndroid Build Coastguard Worker 
617*cc02d7e2SAndroid Build Coastguard Worker #ifdef GRPC_PHP_DEBUG
618*cc02d7e2SAndroid Build Coastguard Worker 
619*cc02d7e2SAndroid Build Coastguard Worker /**
620*cc02d7e2SAndroid Build Coastguard Worker * Clean all channels in the persistent. Test only.
621*cc02d7e2SAndroid Build Coastguard Worker * @return void
622*cc02d7e2SAndroid Build Coastguard Worker */
PHP_METHOD(Channel,cleanPersistentList)623*cc02d7e2SAndroid Build Coastguard Worker PHP_METHOD(Channel, cleanPersistentList) {
624*cc02d7e2SAndroid Build Coastguard Worker   zend_hash_clean(&grpc_persistent_list);
625*cc02d7e2SAndroid Build Coastguard Worker   zend_hash_clean(&grpc_target_upper_bound_map);
626*cc02d7e2SAndroid Build Coastguard Worker }
627*cc02d7e2SAndroid Build Coastguard Worker 
grpc_connectivity_state_name(grpc_connectivity_state state)628*cc02d7e2SAndroid Build Coastguard Worker char *grpc_connectivity_state_name(grpc_connectivity_state state) {
629*cc02d7e2SAndroid Build Coastguard Worker  switch (state) {
630*cc02d7e2SAndroid Build Coastguard Worker    case GRPC_CHANNEL_IDLE:
631*cc02d7e2SAndroid Build Coastguard Worker      return "IDLE";
632*cc02d7e2SAndroid Build Coastguard Worker    case GRPC_CHANNEL_CONNECTING:
633*cc02d7e2SAndroid Build Coastguard Worker      return "CONNECTING";
634*cc02d7e2SAndroid Build Coastguard Worker    case GRPC_CHANNEL_READY:
635*cc02d7e2SAndroid Build Coastguard Worker      return "READY";
636*cc02d7e2SAndroid Build Coastguard Worker    case GRPC_CHANNEL_TRANSIENT_FAILURE:
637*cc02d7e2SAndroid Build Coastguard Worker      return "TRANSIENT_FAILURE";
638*cc02d7e2SAndroid Build Coastguard Worker    case GRPC_CHANNEL_SHUTDOWN:
639*cc02d7e2SAndroid Build Coastguard Worker      return "SHUTDOWN";
640*cc02d7e2SAndroid Build Coastguard Worker  }
641*cc02d7e2SAndroid Build Coastguard Worker  return "UNKNOWN";
642*cc02d7e2SAndroid Build Coastguard Worker }
643*cc02d7e2SAndroid Build Coastguard Worker 
644*cc02d7e2SAndroid Build Coastguard Worker /**
645*cc02d7e2SAndroid Build Coastguard Worker * Return the info about the current channel. Test only.
646*cc02d7e2SAndroid Build Coastguard Worker * @return array
647*cc02d7e2SAndroid Build Coastguard Worker */
PHP_METHOD(Channel,getChannelInfo)648*cc02d7e2SAndroid Build Coastguard Worker PHP_METHOD(Channel, getChannelInfo) {
649*cc02d7e2SAndroid Build Coastguard Worker   wrapped_grpc_channel *channel =
650*cc02d7e2SAndroid Build Coastguard Worker     PHP_GRPC_GET_WRAPPED_OBJECT(wrapped_grpc_channel, getThis());
651*cc02d7e2SAndroid Build Coastguard Worker   array_init(return_value);
652*cc02d7e2SAndroid Build Coastguard Worker    // Info about the target
653*cc02d7e2SAndroid Build Coastguard Worker   PHP_GRPC_ADD_STRING_TO_ARRAY(return_value, "target",
654*cc02d7e2SAndroid Build Coastguard Worker               sizeof("target"), channel->wrapper->target, true);
655*cc02d7e2SAndroid Build Coastguard Worker   // Info about the upper bound for the target
656*cc02d7e2SAndroid Build Coastguard Worker   target_bound_le_t* target_bound_status =
657*cc02d7e2SAndroid Build Coastguard Worker     update_and_get_target_upper_bound(channel->wrapper->target, -1);
658*cc02d7e2SAndroid Build Coastguard Worker   PHP_GRPC_ADD_LONG_TO_ARRAY(return_value, "target_upper_bound",
659*cc02d7e2SAndroid Build Coastguard Worker     sizeof("target_upper_bound"), target_bound_status->upper_bound);
660*cc02d7e2SAndroid Build Coastguard Worker   PHP_GRPC_ADD_LONG_TO_ARRAY(return_value, "target_current_size",
661*cc02d7e2SAndroid Build Coastguard Worker     sizeof("target_current_size"), target_bound_status->current_count);
662*cc02d7e2SAndroid Build Coastguard Worker   // Info about key
663*cc02d7e2SAndroid Build Coastguard Worker   PHP_GRPC_ADD_STRING_TO_ARRAY(return_value, "key",
664*cc02d7e2SAndroid Build Coastguard Worker               sizeof("key"), channel->wrapper->key, true);
665*cc02d7e2SAndroid Build Coastguard Worker   // Info about persistent channel ref_count
666*cc02d7e2SAndroid Build Coastguard Worker   PHP_GRPC_ADD_LONG_TO_ARRAY(return_value, "ref_count",
667*cc02d7e2SAndroid Build Coastguard Worker               sizeof("ref_count"), channel->wrapper->ref_count);
668*cc02d7e2SAndroid Build Coastguard Worker   // Info about connectivity status
669*cc02d7e2SAndroid Build Coastguard Worker   int state =
670*cc02d7e2SAndroid Build Coastguard Worker       grpc_channel_check_connectivity_state(channel->wrapper->wrapped, (int)0);
671*cc02d7e2SAndroid Build Coastguard Worker   // It should be set to 'true' in PHP 5.6.33
672*cc02d7e2SAndroid Build Coastguard Worker   PHP_GRPC_ADD_LONG_TO_ARRAY(return_value, "connectivity_status",
673*cc02d7e2SAndroid Build Coastguard Worker               sizeof("connectivity_status"), state);
674*cc02d7e2SAndroid Build Coastguard Worker   PHP_GRPC_ADD_STRING_TO_ARRAY(return_value, "ob",
675*cc02d7e2SAndroid Build Coastguard Worker               sizeof("ob"),
676*cc02d7e2SAndroid Build Coastguard Worker               grpc_connectivity_state_name(state), true);
677*cc02d7e2SAndroid Build Coastguard Worker   // Info about the channel is closed or not
678*cc02d7e2SAndroid Build Coastguard Worker   PHP_GRPC_ADD_BOOL_TO_ARRAY(return_value, "is_valid",
679*cc02d7e2SAndroid Build Coastguard Worker               sizeof("is_valid"), (channel->wrapper == NULL));
680*cc02d7e2SAndroid Build Coastguard Worker }
681*cc02d7e2SAndroid Build Coastguard Worker 
682*cc02d7e2SAndroid Build Coastguard Worker /**
683*cc02d7e2SAndroid Build Coastguard Worker * Return an array of all channels in the persistent list. Test only.
684*cc02d7e2SAndroid Build Coastguard Worker * @return array
685*cc02d7e2SAndroid Build Coastguard Worker */
PHP_METHOD(Channel,getPersistentList)686*cc02d7e2SAndroid Build Coastguard Worker PHP_METHOD(Channel, getPersistentList) {
687*cc02d7e2SAndroid Build Coastguard Worker   array_init(return_value);
688*cc02d7e2SAndroid Build Coastguard Worker   zval *data;
689*cc02d7e2SAndroid Build Coastguard Worker   PHP_GRPC_HASH_FOREACH_VAL_START(&grpc_persistent_list, data)
690*cc02d7e2SAndroid Build Coastguard Worker     php_grpc_zend_resource *rsrc  =
691*cc02d7e2SAndroid Build Coastguard Worker                 (php_grpc_zend_resource*) PHP_GRPC_HASH_VALPTR_TO_VAL(data)
692*cc02d7e2SAndroid Build Coastguard Worker     if (rsrc == NULL) {
693*cc02d7e2SAndroid Build Coastguard Worker       break;
694*cc02d7e2SAndroid Build Coastguard Worker     }
695*cc02d7e2SAndroid Build Coastguard Worker     channel_persistent_le_t* le = rsrc->ptr;
696*cc02d7e2SAndroid Build Coastguard Worker     zval* ret_arr;
697*cc02d7e2SAndroid Build Coastguard Worker     PHP_GRPC_MAKE_STD_ZVAL(ret_arr);
698*cc02d7e2SAndroid Build Coastguard Worker     array_init(ret_arr);
699*cc02d7e2SAndroid Build Coastguard Worker     // Info about the target
700*cc02d7e2SAndroid Build Coastguard Worker     PHP_GRPC_ADD_STRING_TO_ARRAY(ret_arr, "target",
701*cc02d7e2SAndroid Build Coastguard Worker                 sizeof("target"), le->channel->target, true);
702*cc02d7e2SAndroid Build Coastguard Worker     // Info about the upper bound for the target
703*cc02d7e2SAndroid Build Coastguard Worker     target_bound_le_t* target_bound_status =
704*cc02d7e2SAndroid Build Coastguard Worker       update_and_get_target_upper_bound(le->channel->target, -1);
705*cc02d7e2SAndroid Build Coastguard Worker     PHP_GRPC_ADD_LONG_TO_ARRAY(ret_arr, "target_upper_bound",
706*cc02d7e2SAndroid Build Coastguard Worker       sizeof("target_upper_bound"), target_bound_status->upper_bound);
707*cc02d7e2SAndroid Build Coastguard Worker     PHP_GRPC_ADD_LONG_TO_ARRAY(ret_arr, "target_current_size",
708*cc02d7e2SAndroid Build Coastguard Worker       sizeof("target_current_size"), target_bound_status->current_count);
709*cc02d7e2SAndroid Build Coastguard Worker     // Info about key
710*cc02d7e2SAndroid Build Coastguard Worker     PHP_GRPC_ADD_STRING_TO_ARRAY(ret_arr, "key",
711*cc02d7e2SAndroid Build Coastguard Worker                 sizeof("key"), le->channel->key, true);
712*cc02d7e2SAndroid Build Coastguard Worker     // Info about persistent channel ref_count
713*cc02d7e2SAndroid Build Coastguard Worker     PHP_GRPC_ADD_LONG_TO_ARRAY(ret_arr, "ref_count",
714*cc02d7e2SAndroid Build Coastguard Worker                 sizeof("ref_count"), le->channel->ref_count);
715*cc02d7e2SAndroid Build Coastguard Worker     // Info about connectivity status
716*cc02d7e2SAndroid Build Coastguard Worker     int state =
717*cc02d7e2SAndroid Build Coastguard Worker         grpc_channel_check_connectivity_state(le->channel->wrapped, (int)0);
718*cc02d7e2SAndroid Build Coastguard Worker     // It should be set to 'true' in PHP 5.6.33
719*cc02d7e2SAndroid Build Coastguard Worker     PHP_GRPC_ADD_LONG_TO_ARRAY(ret_arr, "connectivity_status",
720*cc02d7e2SAndroid Build Coastguard Worker                 sizeof("connectivity_status"), state);
721*cc02d7e2SAndroid Build Coastguard Worker     PHP_GRPC_ADD_STRING_TO_ARRAY(ret_arr, "ob",
722*cc02d7e2SAndroid Build Coastguard Worker                 sizeof("ob"),
723*cc02d7e2SAndroid Build Coastguard Worker                 grpc_connectivity_state_name(state), true);
724*cc02d7e2SAndroid Build Coastguard Worker     add_assoc_zval(return_value, le->channel->key, ret_arr);
725*cc02d7e2SAndroid Build Coastguard Worker     PHP_GRPC_FREE_STD_ZVAL(ret_arr);
726*cc02d7e2SAndroid Build Coastguard Worker   PHP_GRPC_HASH_FOREACH_END()
727*cc02d7e2SAndroid Build Coastguard Worker }
728*cc02d7e2SAndroid Build Coastguard Worker #endif
729*cc02d7e2SAndroid Build Coastguard Worker 
730*cc02d7e2SAndroid Build Coastguard Worker 
731*cc02d7e2SAndroid Build Coastguard Worker ZEND_BEGIN_ARG_INFO_EX(arginfo_construct, 0, 0, 2)
732*cc02d7e2SAndroid Build Coastguard Worker   ZEND_ARG_INFO(0, target)
733*cc02d7e2SAndroid Build Coastguard Worker   ZEND_ARG_INFO(0, args)
734*cc02d7e2SAndroid Build Coastguard Worker ZEND_END_ARG_INFO()
735*cc02d7e2SAndroid Build Coastguard Worker 
736*cc02d7e2SAndroid Build Coastguard Worker ZEND_BEGIN_ARG_INFO_EX(arginfo_getTarget, 0, 0, 0)
737*cc02d7e2SAndroid Build Coastguard Worker ZEND_END_ARG_INFO()
738*cc02d7e2SAndroid Build Coastguard Worker 
739*cc02d7e2SAndroid Build Coastguard Worker ZEND_BEGIN_ARG_INFO_EX(arginfo_getConnectivityState, 0, 0, 0)
740*cc02d7e2SAndroid Build Coastguard Worker   ZEND_ARG_INFO(0, try_to_connect)
741*cc02d7e2SAndroid Build Coastguard Worker ZEND_END_ARG_INFO()
742*cc02d7e2SAndroid Build Coastguard Worker 
743*cc02d7e2SAndroid Build Coastguard Worker ZEND_BEGIN_ARG_INFO_EX(arginfo_watchConnectivityState, 0, 0, 2)
744*cc02d7e2SAndroid Build Coastguard Worker   ZEND_ARG_INFO(0, last_state)
745*cc02d7e2SAndroid Build Coastguard Worker   ZEND_ARG_INFO(0, deadline)
746*cc02d7e2SAndroid Build Coastguard Worker ZEND_END_ARG_INFO()
747*cc02d7e2SAndroid Build Coastguard Worker 
748*cc02d7e2SAndroid Build Coastguard Worker ZEND_BEGIN_ARG_INFO_EX(arginfo_close, 0, 0, 0)
749*cc02d7e2SAndroid Build Coastguard Worker ZEND_END_ARG_INFO()
750*cc02d7e2SAndroid Build Coastguard Worker 
751*cc02d7e2SAndroid Build Coastguard Worker #ifdef GRPC_PHP_DEBUG
752*cc02d7e2SAndroid Build Coastguard Worker ZEND_BEGIN_ARG_INFO_EX(arginfo_getChannelInfo, 0, 0, 0)
753*cc02d7e2SAndroid Build Coastguard Worker ZEND_END_ARG_INFO()
754*cc02d7e2SAndroid Build Coastguard Worker 
755*cc02d7e2SAndroid Build Coastguard Worker ZEND_BEGIN_ARG_INFO_EX(arginfo_cleanPersistentList, 0, 0, 0)
756*cc02d7e2SAndroid Build Coastguard Worker ZEND_END_ARG_INFO()
757*cc02d7e2SAndroid Build Coastguard Worker 
758*cc02d7e2SAndroid Build Coastguard Worker ZEND_BEGIN_ARG_INFO_EX(arginfo_getPersistentList, 0, 0, 0)
759*cc02d7e2SAndroid Build Coastguard Worker ZEND_END_ARG_INFO()
760*cc02d7e2SAndroid Build Coastguard Worker #endif
761*cc02d7e2SAndroid Build Coastguard Worker 
762*cc02d7e2SAndroid Build Coastguard Worker 
763*cc02d7e2SAndroid Build Coastguard Worker static zend_function_entry channel_methods[] = {
764*cc02d7e2SAndroid Build Coastguard Worker   PHP_ME(Channel, __construct, arginfo_construct,
765*cc02d7e2SAndroid Build Coastguard Worker          ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
766*cc02d7e2SAndroid Build Coastguard Worker   PHP_ME(Channel, getTarget, arginfo_getTarget,
767*cc02d7e2SAndroid Build Coastguard Worker          ZEND_ACC_PUBLIC)
768*cc02d7e2SAndroid Build Coastguard Worker   PHP_ME(Channel, getConnectivityState, arginfo_getConnectivityState,
769*cc02d7e2SAndroid Build Coastguard Worker          ZEND_ACC_PUBLIC)
770*cc02d7e2SAndroid Build Coastguard Worker   PHP_ME(Channel, watchConnectivityState, arginfo_watchConnectivityState,
771*cc02d7e2SAndroid Build Coastguard Worker          ZEND_ACC_PUBLIC)
772*cc02d7e2SAndroid Build Coastguard Worker   PHP_ME(Channel, close, arginfo_close,
773*cc02d7e2SAndroid Build Coastguard Worker          ZEND_ACC_PUBLIC)
774*cc02d7e2SAndroid Build Coastguard Worker   #ifdef GRPC_PHP_DEBUG
775*cc02d7e2SAndroid Build Coastguard Worker   PHP_ME(Channel, getChannelInfo, arginfo_getChannelInfo,
776*cc02d7e2SAndroid Build Coastguard Worker          ZEND_ACC_PUBLIC)
777*cc02d7e2SAndroid Build Coastguard Worker   PHP_ME(Channel, cleanPersistentList, arginfo_cleanPersistentList,
778*cc02d7e2SAndroid Build Coastguard Worker          ZEND_ACC_PUBLIC)
779*cc02d7e2SAndroid Build Coastguard Worker   PHP_ME(Channel, getPersistentList, arginfo_getPersistentList,
780*cc02d7e2SAndroid Build Coastguard Worker          ZEND_ACC_PUBLIC)
781*cc02d7e2SAndroid Build Coastguard Worker   #endif
782*cc02d7e2SAndroid Build Coastguard Worker   PHP_FE_END
783*cc02d7e2SAndroid Build Coastguard Worker };
784*cc02d7e2SAndroid Build Coastguard Worker 
GRPC_STARTUP_FUNCTION(channel)785*cc02d7e2SAndroid Build Coastguard Worker GRPC_STARTUP_FUNCTION(channel) {
786*cc02d7e2SAndroid Build Coastguard Worker   zend_class_entry ce;
787*cc02d7e2SAndroid Build Coastguard Worker   INIT_CLASS_ENTRY(ce, "Grpc\\Channel", channel_methods);
788*cc02d7e2SAndroid Build Coastguard Worker   ce.create_object = create_wrapped_grpc_channel;
789*cc02d7e2SAndroid Build Coastguard Worker   grpc_ce_channel = zend_register_internal_class(&ce TSRMLS_CC);
790*cc02d7e2SAndroid Build Coastguard Worker   gpr_mu_init(&global_persistent_list_mu);
791*cc02d7e2SAndroid Build Coastguard Worker   le_plink = zend_register_list_destructors_ex(
792*cc02d7e2SAndroid Build Coastguard Worker       NULL, php_grpc_channel_plink_dtor, "Persistent Channel", module_number);
793*cc02d7e2SAndroid Build Coastguard Worker   ZEND_HASH_INIT(&grpc_persistent_list, 20, EG(persistent_list).pDestructor, 1);
794*cc02d7e2SAndroid Build Coastguard Worker   // Register the target->upper_bound map.
795*cc02d7e2SAndroid Build Coastguard Worker   le_bound = zend_register_list_destructors_ex(
796*cc02d7e2SAndroid Build Coastguard Worker       NULL, php_grpc_target_bound_dtor, "Target Bound", module_number);
797*cc02d7e2SAndroid Build Coastguard Worker   ZEND_HASH_INIT(&grpc_target_upper_bound_map, 20, EG(persistent_list).pDestructor, 1);
798*cc02d7e2SAndroid Build Coastguard Worker 
799*cc02d7e2SAndroid Build Coastguard Worker   PHP_GRPC_INIT_HANDLER(wrapped_grpc_channel, channel_ce_handlers);
800*cc02d7e2SAndroid Build Coastguard Worker   return SUCCESS;
801*cc02d7e2SAndroid Build Coastguard Worker }
802